【问题标题】:How to cause a component to re render in react when using a hook which holds some state使用保持某些状态的钩子时如何使组件重新渲染
【发布时间】:2020-07-20 10:00:10
【问题描述】:

我正在尝试在道具更改时重新渲染组件。我的组件使用一个自定义钩子来保存表单的状态。在 useEffect 中,每当名为 refresh 的道具发生变化时,我想重新呈现页面。我尝试了无数解决方案,包括制作 forceUpdate 函数并在道具更改时调用它,我尝试更改状态以便组件重新渲染,但我的 for 中的信息不清楚。下面是我的代码。

组件:

const CustomerInformationForm = (props) => {
  const [triggerRefresh, setTriggerRefresh] = useState();
  const initialState = {
    name: {
      value: "",
      isValid: false,
    },
    phone: {
      value: "",
      isValid: false,
    },
    address: {
      value: "",
      isValid: true,
    },
  };

  const initialValidity = false;

  useEffect(() => {
    console.log("customerinfo refreshing");
    setTriggerRefresh(props.refresh);
  }, [props.refresh]);

  let [formState, inputHandler] = useForm(
    initialState,
    initialValidity
  );
  
  return (
    <div>
      <h3>Customer Information</h3>
      <form className="customer-information_form">
        <Input
          id="name"
          label="Name"
          type="text"
          element="input"
          validators={[VALIDATOR_REQUIRE()]}
          errorText="Please enter a valid name."
          onInput={inputHandler}
          onChange={props.customerInfo(formState)}
        />
        <Input
          type="text"
          element="input"
          id="phone"
          label="Phone"
          validators={[VALIDATOR_MINLENGTH(8)]}
          errorText="Please enter a valid phone number."
          onInput={inputHandler}
          onChange={props.customerInfo(formState)}
        />
        <Input
          type="text"
          element="input"
          id="address"
          label="Address"
          validators={[]}
          onInput={inputHandler}
          onChange={props.customerInfo(formState)}
        />
      </form>
    </div>
  );
};

export default CustomerInformationForm;

自定义钩子:

import { useCallback, useReducer } from "react";

const formReducer = (state, action) => {
  switch (action.type) {
    case "INPUT_CHANGE":
      let formIsValid = true;
      for (const inputId in state.inputs) {
        if (!state.inputs[inputId]) {
          continue;
        }
        if (inputId === action.inputId) {
          formIsValid = formIsValid && action.isValid;
        } else {
          formIsValid = formIsValid && state.inputs[inputId].isValid;
        }
      }
      return {
        ...state,
        inputs: {
          ...state.inputs,
          [action.inputId]: { value: action.value, isValid: action.isValid },
        },
        isValid: formIsValid,
      };
    case "SET_DATA":
      return {
        inputs: action.inputs,
        isValid: action.formIsValid,
      };
    default:
      return state;
  }
};

export const useForm = (initialInputs, initialValidity) => {
  const [formState, dispatch] = useReducer(formReducer, {
    inputs: initialInputs,
    isValid: initialValidity,
  });

  const inputHandler = useCallback((id, value, isValid) => {
    dispatch({
      type: "INPUT_CHANGE",
      value: value,
      isValid: isValid,
      inputId: id,
    });
  }, []);

  const setFormData = useCallback((inputData, formValidity) => {
    dispatch({
      type: "SET_DATA",
      inputs: inputData,
      formIsValid: formValidity,
    });
  }, []);

 
  return [formState, inputHandler, setFormData,];
};

关于我可以做些什么来让表单重新呈现为空的任何解决方案??

【问题讨论】:

    标签: reactjs react-hooks


    【解决方案1】:

    我认为最好的方法是使用你的钩子返回的 setFormData 方法(你在 CustomerInformationForm 组件中省略了它)。

    然后你可以在表单中调用它,当一个效果中满足某些条件时:

    const initialState = useRef({
        name: {
          value: "",
          isValid: false,
        },
        phone: {
          value: "",
          isValid: false,
        },
        address: {
          value: "",
          isValid: true,
        },
      });
    
    let [formState, inputHandler, setFormData] = useForm(
        initialState,
        initialValidity
    );
    
     useEffect(() => {
        console.log("customerinfo refreshing");
        setTriggerRefresh(props.refresh);
        setFormData(initialState.current);
     }, [props.refresh]);
    

    您还可以将initialState 值与useRef 一起存储,以避免不必要地重新运行效果。

    【讨论】:

    • 这仍然不会将我表单上的所有输入更改为空。我的自定义钩子的功能可能有问题吗?
    • 你能在codesandbox的一个小例子中重现它吗?
    猜你喜欢
    • 2021-04-04
    • 1970-01-01
    • 2019-11-24
    • 2020-04-29
    • 2021-02-21
    • 2018-08-03
    • 1970-01-01
    • 1970-01-01
    • 2014-09-29
    相关资源
    最近更新 更多