REACT:如何创建一个可重用的自定义挂钩,其功能和效果可以更改并对主机组件数据的更改做出反应

REACT: How to create a reusable custom hook with functions and effects that can change & react to changes in a host component's data

我有一个用于编辑订单信息(客户名称、商品、地址等)的 React App 组件

这里是简化版...

function App({ orderInfo }) {

    // App state ('data' has customer name, address, user role, etc.)
    const [data, setData] = useState(orderInfo);    

    // Address-related functions & effects:
    function isEditableAddress() { return data.user.role === 'EDITOR' }

    useEffect(function loadSuburb() {
        // (Load suburb when postcode changes)
        (async () => {
            const response = await fetch(`/myApp/getSuburb.do&postCode=${data.postcode}`);
            const suburb = await response.json();
            setData((prev) => ({...prev, suburb: suburb}));
        })();
    },[data.postcode]);
    
    // -- Non-address functions & effects:
    // [here go more functions & effects that also work with 'data'...]
    
    // Sub-components, one of which works with address...
    return (
        <>
            <AddressComponent
                data={data}
                isEditableAddress={isEditableAddress()}
                onChangePostcode={val => {setData((prev) => ({...prev, postcode: val}))}}
            />
            <OtherComponent
                data={data}
                onChangeFirstname={val => {setData((prev) => ({...prev, firstname: val}))}}
            />
        </>
    );
        
}

我现在有另一个应用程序需要使用 AddressComponent 和相同的地址效果和功能(其中比上面的示例更多)所以我倾向于将它们移动到...自定义挂钩中?

我的问题是:

  1. 如何让 'useEffect(fn, [data.postcode])' 在父组件位于其自己的自定义挂钩中后对数据做出反应并更新数据? (我尝试将 'data' 和 'setData' 作为属性传递到我的 useAddress 自定义挂钩中,但没有成功。)

  2. 如何将辅助函数暴露给父组件?我是否只是 return 它们来自自定义挂钩,并将它们设置在主组件中,如:{isEditableAddress} = useAddressHook();

或者我对自定义挂钩的期望很高?最好的方法是什么?我正在努力寻找以这种方式工作的自定义挂钩的示例。

自定义挂钩旨在完全按照您的需要^隔离和重用其逻辑。您可以在 React 官方文档中阅读更多关于 building custom hooks 的信息。您的案例是构建自定义挂钩的典型案例:隔离状态、效果和一些函数以在一个挂钩中对状态进行操作。你可以这样做:

const useOrderData = (initialState) => {
  const [orderData, setOrderData] = useState(initialState)

  useEffect(() => {
    // load suburb
    setOrderData()
  }, [data.postcode])

  // other effects in case you need them

  const isEditableAddress = orderData.user.role === 'EDITOR'

  return [orderData, { isEditableAddress }]
}

您还可以向自定义挂钩添加一些函数,我将 isEditableAddress 更改为变量,因为每次数据更改时它的值都会更新。使用钩子将如下所示:

const [data, { isEditableAddress }] = useOrderData({})

检查这个site,有很多自定义钩子示例