是否可以使用React中的useState()钩子在组件之间共享状态



我在React中试用了新的Hook功能。考虑到我有以下两个组件(使用React Hooks(-

const HookComponent = () => {
const [username, setUsername] = useState('Abrar');
const [count, setState] = useState();
const handleChange = (e) => {
setUsername(e.target.value);
}
return (
<div>
<input name="userName" value={username} onChange={handleChange}/>
<p>{username}</p>
<p>From HookComponent: {count}</p>
</div>
)
}

const HookComponent2 = () => {
const [count, setCount] = useState(999);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}

Hooks声称解决了组件之间共享状态逻辑的问题,但我发现HookComponentHookComponent2之间的状态是不可共享的。例如,CCD_ 4中的CCD_ 3的改变不呈现CCD_ 5中的改变。

是否可以使用useState()挂钩在组件之间共享状态?

如果您引用的是组件状态,那么钩子将无法帮助您在组件之间共享它。组件状态是组件的本地状态。如果您的状态存在于上下文中,那么useContext钩子会有所帮助。

从根本上说,我认为你误解了这句话;在组件之间共享有状态逻辑";。状态逻辑与状态不同。状态逻辑是指修改状态的东西。例如,订阅componentDidMount()中的存储并且在componentWillUnmount()中取消订阅的组件。这种订阅/取消订阅行为可以在钩子中实现,需要这种行为的组件可以直接使用钩子。

如果你想在组件之间共享状态,有多种方法可以做到这一点,每种方法都有自己的优点:

1.提升状态向上

将状态提升到两个组件的共同祖先组件。

function Ancestor() {
const [count, setCount] = useState(999);
return <>
<DescendantA count={count} onCountChange={setCount} />
<DescendantB count={count} onCountChange={setCount} />
</>;
}

这种状态共享方法与传统的使用状态的方式没有本质的不同,钩子只是为我们提供了一种不同的声明组件状态的方式。

2.上下文

如果子体在组件层次结构中太深,并且您不想将状态传递给太多层,则可以使用Context API。

有一个useContext钩子,您可以在子组件中利用它。

3.外部状态管理解决方案

像Redux或Mobx这样的国家管理图书馆。然后,您的状态将存在于React之外的存储中,组件可以连接/订阅该存储以接收更新。

在没有任何外部状态管理库的情况下,这是可能的。只需使用一个简单的可观察实现:

function makeObservable(target) {
let listeners = []; // initial listeners can be passed an an argument aswell
let value = target;
function get() {
return value;
}
function set(newValue) {
if (value === newValue) return;
value = newValue;
listeners.forEach((l) => l(value));
}
function subscribe(listenerFunc) {
listeners.push(listenerFunc);
return () => unsubscribe(listenerFunc); // will be used inside React.useEffect
}
function unsubscribe(listenerFunc) {
listeners = listeners.filter((l) => l !== listenerFunc);
}
return {
get,
set,
subscribe,
};
}

然后创建一个存储并使用useEffect:中的subscribe将其挂起以进行反应

const userStore = makeObservable({ name: "user", count: 0 });
const useUser = () => {
const [user, setUser] = React.useState(userStore.get());
React.useEffect(() => {
return userStore.subscribe(setUser);
}, []);
const actions = React.useMemo(() => {
return {
setName: (name) => userStore.set({ ...user, name }),
incrementCount: () => userStore.set({ ...user, count: user.count + 1 }),
decrementCount: () => userStore.set({ ...user, count: user.count - 1 }),
}
}, [user])
return {
state: user,
actions
}
}

这应该奏效。无需React.Context或提升状态

这可以使用useBetween挂钩。

请参阅代码沙盒

import React, { useState } from 'react';
import { useBetween } from 'use-between';
const useShareableState = () => {
const [username, setUsername] = useState('Abrar');
const [count, setCount] = useState(0);
return {
username,
setUsername,
count,
setCount
}
}

const HookComponent = () => {
const { username, setUsername, count } = useBetween(useShareableState);
const handleChange = (e) => {
setUsername(e.target.value);
}
return (
<div>
<input name="userName" value={username} onChange={handleChange}/>
<p>{username}</p>
<p>From HookComponent: {count}</p>
</div>
)
}

const HookComponent2 = () => {
const { count, setCount } = useBetween(useShareableState);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}

我们将React钩子有状态逻辑从HookComponent移动到useShareableState。我们在每个组件中使用useBetween来调用useShareableState

useBetween是调用任何钩子的方法。但是这样状态就不会存储在React组件中。对于同一个钩子,调用的结果将是相同的。因此,我们可以在不同的组件中调用一个钩子,并在一个状态下协同工作。当更新共享状态时,使用它的每个组件也将更新。

免责声明:我是use-between软件包的作者

单据状态:

我们从React导入useState Hook。它使我们能够在函数组件中保持局部状态。

没有提到状态可以在组件之间共享,useState钩子只是为您提供了一种更快的方法,可以在一条指令中声明状态字段及其对应的setter。

我创建了hooksy,它可以让你做到这一点-https://github.com/pie6k/hooksy

import { createStore } from 'hooksy';
interface UserData {
username: string;
}
const defaultUser: UserData = { username: 'Foo' };
export const [useUserStore] = createStore(defaultUser); // we've created store with initial value.
// useUserStore has the same signature like react useState hook, but the state will be shared across all components using it

稍后在任何组件中

import React from 'react';
import { useUserStore } from './userStore';
export function UserInfo() {
const [user, setUser] = useUserStore(); // use it the same way like useState, but have state shared across any component using it (eg. if any of them will call setUser - all other components using it will get re-rendered with new state)
function login() {
setUser({ username: 'Foo' })
}
return (
<div>
{!user && <strong>You're logged out<button onPress={login}>Login</button></strong>}
{user && <strong>Logged as <strong>{user.username}</strong></strong>}
</div>
);
}

使用钩子是不可能的。我建议你看看反应容易的状态。https://github.com/solkimicreb/react-easy-state

我在大型应用程序中使用它,它就像一个魅力。

我要为这个下地狱:

// src/hooks/useMessagePipe.ts
import { useReducer } from 'react'
let message = undefined
export default function useMessagePipe() {
const triggerRender = useReducer((bool) => !bool, true)[1]
function update(term: string) {
message = term.length > 0 ? term : undefined
triggerRender()
}
return {message: message, sendMessage: update}
}

完整解释如下:https://stackoverflow.com/a/72917627/1246547


是的,这是我能想出的解决特定用例的最脏、最简洁的方法。是的,对于一种干净的方式,你可能想学习如何useContext,或者看看react easy state或useBetween(低占地面积解决方案(,以及flux或redux(真实情况(。

您仍然需要将您的状态提升到HookComponent1和HookComponent2的祖先组件。这就是你以前共享状态的方式,最新的hookapi不会改变它

相关内容

  • 没有找到相关文章

最新更新