React When does rendering happen

525 views Asked by At

My project use dvajs(Based on redux and redux-saga), The code below is to send a request after clicking the button, change the status through connect, and then call the ant design component message.error an message.success(Similar to alert) to remind

import type { Dispatch } from 'umi';
import ProForm, { ProFormText } from '@ant-design/pro-form';
import { message } from 'antd';

const tip = (type: string, content: string) => {
  if (type === 'error') message.error(content, 5);
  else message.success(content, 5);
};

const RegisterFC: React.FC<RegisterProps> = (props) => {
  const { registerResponseInfo = {}, submitting, dispatch } = props;
  const { status } = registerResponseInfo;

  const handleSubmit = (values: RegisterParamsType) => {
    dispatch({
      type: 'register/register',
      payload: { ...values },
   });
};      

  return (
    <div>
      <ProForm
         onFinish={(values) => {
            handleSubmit(values as RegisterParamsType);
            return Promise.resolve();
    }}
       >
       <ProFormText/>
       ...
      {
        status === '1' && !submitting && (
          tip('error',
            intl.formatMessage({
              id: 'pages.register.status1.message',
              defaultMessage: 'error'
            })
          )
        )
      }
    <<ProForm>/>
    </div>
  )
}

const p = ({ register, loading }: { register: RegisterResponseInfo, loading: Loading; }) => {
  console.log(loading);
  return {
    registerResponseInfo: register,
    submitting: loading.effects['register/register'],
  };
};

export default connect(p)(RegisterFC);

When I click the button, the console prompts:

Warning: Render methods should be a pure function of props and state; triggering nested component updates from render is not allowed. If necessary, trigger nested updates in componentDidUpdate.

Doesn't the component re-render when the state changes? Does the tip function change the state?

1

There are 1 answers

0
Linda Paiste On BEST ANSWER

Solution: Call tip Outside of return

tip is just a function that you are calling. You should call it outside of the return JSX section of your code. I think it makes the most sense to call it inside of a useEffect hook with dependencies on status and submitting. The effect runs each time that status or submitting changes. If status is 1 and submitting is falsy, then we call tip.

const RegisterFC: React.FC<RegisterProps> = (props) => {
    const { registerResponseInfo = {}, submitting, dispatch } = props;
    const { status } = registerResponseInfo;

    const handleSubmit = (values: RegisterParamsType) => {
        dispatch({
            type: 'register/register',
            payload: { ...values },
        });
    };

    React.useEffect(() => {
        if (status === '1' && !submitting) {
            tip('error',
                intl.formatMessage({
                    id: 'pages.register.status1.message',
                    defaultMessage: 'error'
                })
            );
        }
    }, [status, submitting]);

    return (
        <div>...</div>
    )
}

Explanation

Render methods should be a pure function of props and state

The render section of a component (render() in class component or return in a function component) is where you create the JSX (React HTML) markup for your component based on the current values of props and state. It should not have any side effects. It creates and returns JSX and that's it.

Calling tip is a side effect since it modifies the global antd messsage object. That means it shouldn't be in the render section of the code. Side effects are generally handled inside of useEffect hooks.

You are trying to conditionally render tip like you would conditionally render a component. The problem is that tip is not a component. A function component is a function which returns a JSX Element. tip is a void function that returns nothing, so you cannot render it.