我得到这个警告在反应:

index.js:1 Warning: Cannot update a component (`ConnectFunction`) 
while rendering a different component (`Register`). To locate the 
bad setState() call inside `Register` 

我去了堆栈跟踪中指出的位置,并删除了所有设置状态,但警告仍然存在。这可能发生在redux调度?

我的代码:

register.js

class Register extends Component {
  render() {
    if( this.props.registerStatus === SUCCESS) { 
      // Reset register status to allow return to register page
      this.props.dispatch( resetRegisterStatus())  # THIS IS THE LINE THAT CAUSES THE ERROR ACCORDING TO THE STACK TRACE
      return <Redirect push to = {HOME}/>
    }
    return (
      <div style = {{paddingTop: "180px", background: 'radial-gradient(circle, rgba(106,103,103,1) 0%, rgba(36,36,36,1) 100%)', height: "100vh"}}>
        <RegistrationForm/>
      </div>
    );
  }
}

function mapStateToProps( state ) {
  return {
    registerStatus: state.userReducer.registerStatus
  }
}

export default connect ( mapStateToProps ) ( Register );

函数,该函数触发了由register.js调用的registerForm组件中的警告

handleSubmit = async () => {
    if( this.isValidForm() ) { 
      const details = {
        "username": this.state.username,
        "password": this.state.password,
        "email": this.state.email,
        "clearance": this.state.clearance
      }
      await this.props.dispatch( register(details) )
      if( this.props.registerStatus !== SUCCESS && this.mounted ) {
        this.setState( {errorMsg: this.props.registerError})
        this.handleShowError()
      }
    }
    else {
      if( this.mounted ) {
        this.setState( {errorMsg: "Error - registration credentials are invalid!"} )
        this.handleShowError()
      }
    }
  }

堆栈跟踪:


当前回答

我的案例是使用setState回调,而不是setState + useEffect

坏❌

  const closePopover = useCallback(
    () =>
      setOpen((prevOpen) => {
        prevOpen && onOpenChange(false);
        return false;
      }),
    [onOpenChange]
  );

好✅

  const closePopover = useCallback(() => setOpen(false), []);

  useEffect(() => onOpenChange(isOpen), [isOpen, onOpenChange]);

其他回答

我只是遇到了这个问题,在我意识到我做错了什么之前,我花了一些时间去挖掘——我只是没有注意我是如何写我的函数组件的。

我是这样做的:

const LiveMatches = (props: LiveMatchesProps) => {
  const {
    dateMatches,
    draftingConfig,
    sportId,
    getDateMatches,
  } = props;

  if (!dateMatches) {
    const date = new Date();
    getDateMatches({ sportId, date });
  };

  return (<div>{component stuff here..}</div>);
};

在分派getDateMatches()的redux调用之前,我刚刚忘记了使用useEffect。

所以它应该是:

const LiveMatches = (props: LiveMatchesProps) => {
  const {
    dateMatches,
    draftingConfig,
    sportId,
    getDateMatches,
  } = props;

  useEffect(() => {
    if (!dateMatches) {
      const date = new Date();
      getDateMatches({ sportId, date });
    }
  }, [dateMatches, getDateMatches, sportId]);

  return (<div>{component stuff here..}</div>);
};

请仔细阅读错误消息,我的是指向签入组件有一个坏的setState。当我检查时,我有一个不是箭头函数的onpress。

是这样的:

onPress={navigation.navigate("Home", { screen: "HomeScreen" })}

我把它改成了这样:

onPress={() => navigation.navigate("Home", { screen: "HomeScreen" }) }

我的错误信息是:

警告:不能更新组件 (ForwardRef(BaseNavigationContainer)),同时呈现一个不同的 组件(SignIn)。来定位内部错误的setState()调用 中所描述的堆栈跟踪 https://reactjs.org/link/setstate-in-render in SignIn(在SignInScreen.tsx:20)

我的案例是使用setState回调,而不是setState + useEffect

坏❌

  const closePopover = useCallback(
    () =>
      setOpen((prevOpen) => {
        prevOpen && onOpenChange(false);
        return false;
      }),
    [onOpenChange]
  );

好✅

  const closePopover = useCallback(() => setOpen(false), []);

  useEffect(() => onOpenChange(isOpen), [isOpen, onOpenChange]);

在GitHub中遇到类似的问题后,我能够解决这个问题,这让我看到了这条评论,展示了如何精确定位文件中导致错误的确切行。我不知道堆栈跟踪在那里。希望这能帮助到一些人!

请看下面我的解决方案。我只是将函数转换为使用回调。

旧的代码

function TopMenuItems() {
  const dispatch = useDispatch();

  function mountProjectListToReduxStore(projects) {
    const projectDropdown = projects.map((project) => ({
      id: project.id,
      name: project.name,
      organizationId: project.organizationId,
      createdOn: project.createdOn,
      lastModifiedOn: project.lastModifiedOn,
      isComplete: project.isComplete,
    }));
    projectDropdown.sort((a, b) => a.name.localeCompare(b.name));
    dispatch(loadProjectsList(projectDropdown));
    dispatch(setCurrentOrganizationId(projectDropdown[0].organizationId));
  }
};

新代码

function TopMenuItems() {
  const dispatch = useDispatch();

  const mountProjectListToReduxStore = useCallback((projects) => {
    const projectDropdown = projects.map((project) => ({
      id: project.id,
      name: project.name,
      organizationId: project.organizationId,
      createdOn: project.createdOn,
      lastModifiedOn: project.lastModifiedOn,
      isComplete: project.isComplete,
    }));
    projectDropdown.sort((a, b) => a.name.localeCompare(b.name));
    dispatch(loadProjectsList(projectDropdown));
    dispatch(setCurrentOrganizationId(projectDropdown[0].organizationId));
  }, [dispatch]);
};

我认为这很重要。 @Red-Baron在这篇文章中指出:

@machineghost:我认为你误解了这条信息警告的内容。

将更新父节点状态的回调传递给子节点并没有什么错。这一直都很好。

问题是当一个组件在另一个组件中排队更新时,而第一个组件正在呈现。

换句话说,不要这样做:

function SomeChildComponent(props) {
    props.updateSomething();
    return <div />
}

但这是可以的:

function SomeChildComponent(props) {
    // or make a callback click handler and call it in there
    return <button onClick={props.updateSomething}>Click Me</button>
}

而且,正如Dan多次指出的那样,在渲染时在同一个组件中排队更新也很好:

function SomeChildComponent(props) {
  const [number, setNumber] = useState(0);

  if(props.someValue > 10 && number < 5) {
    // queue an update while rendering, equivalent to getDerivedStateFromProps
    setNumber(42);
  }

  return <div>{number}</div>
}