React - 你能从外部函数更新 Unstated 容器状态吗?
React - Can you update an Unstated container state from an external function?
在 Unstated 库的示例中,他们通过与订阅容器的 jsx 按钮交互来更新容器内的状态。
import React from 'react';
import { render } from 'react-dom';
import { Provider, Subscribe, Container } from 'unstated';
type CounterState = {
count: number
};
class CounterContainer extends Container<CounterState> {
state = {
count: 0
};
increment() {
this.setState({ count: this.state.count + 1 });
}
decrement() {
this.setState({ count: this.state.count - 1 });
}
}
function Counter() {
return (
<Subscribe to={[CounterContainer]}>
{counter => (
<div>
<button onClick={() => counter.decrement()}>-</button>
<span>{counter.state.count}</span>
<button onClick={() => counter.increment()}>+</button>
</div>
)}
</Subscribe>
);
}
render(
<Provider>
<Counter />
</Provider>,
document.getElementById('root')
);
有没有办法通过容器外部组件中的函数更新容器内的状态?因此,例如,如果我想在承诺的 return 期间更新状态,我将如何去做。伪代码
login = () => {
let url = baseURL + '/user/login?_format=json';
let data = {
"name": this.state.email,
"pass": this.state.password
};
axios({
url,
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
withCredentials: true,
credentials: 'same-origin',
data,
})
.then(function(result) {
console.log('result:', result);
SET STATE HERE!!!!!!!
counter.increment()
})
.catch(error => console.log('error:', error));
};
这是一个常见问题,针对您的问题有很多解决方案。您需要将函数传递给 child,然后更新 parent。我将 link 回复我之前发布的一个答案。在你的情况下,你在哪里渲染
<Login upParentCounter={this.increment}/>
在登录组件内部
this.props.upParentCounter()
这个问题不是 Unstated 特有的,这也适用于使用 render prop 模式的 React 上下文 API。
login
的问题是它的控制流有缺陷。它无法有效地捕获错误,因为它会抑制错误。并且它把promise封装在里面,这是一个错误,阻止了它被正确测试,对于初学者来说
它可以暴露一个承诺,或者接受一个回调,或者两者兼而有之:
login = async (cb) => {
...
return axios(...)
.then(function(result) {
if (cb)
cb(result);
return result;
})
.catch(error => console.log('error:', error));
}
可用作:
<button onClick={() => login(() => counter.decrement())}>-</button>
或者:
<button onClick={async () => { await login(); counter.decrement(); }}>-</button>
也可以使 login
接受 counter
作为参数,但这会将其耦合到不必要的实现。
在 Unstated 库的示例中,他们通过与订阅容器的 jsx 按钮交互来更新容器内的状态。
import React from 'react';
import { render } from 'react-dom';
import { Provider, Subscribe, Container } from 'unstated';
type CounterState = {
count: number
};
class CounterContainer extends Container<CounterState> {
state = {
count: 0
};
increment() {
this.setState({ count: this.state.count + 1 });
}
decrement() {
this.setState({ count: this.state.count - 1 });
}
}
function Counter() {
return (
<Subscribe to={[CounterContainer]}>
{counter => (
<div>
<button onClick={() => counter.decrement()}>-</button>
<span>{counter.state.count}</span>
<button onClick={() => counter.increment()}>+</button>
</div>
)}
</Subscribe>
);
}
render(
<Provider>
<Counter />
</Provider>,
document.getElementById('root')
);
有没有办法通过容器外部组件中的函数更新容器内的状态?因此,例如,如果我想在承诺的 return 期间更新状态,我将如何去做。伪代码
login = () => {
let url = baseURL + '/user/login?_format=json';
let data = {
"name": this.state.email,
"pass": this.state.password
};
axios({
url,
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
withCredentials: true,
credentials: 'same-origin',
data,
})
.then(function(result) {
console.log('result:', result);
SET STATE HERE!!!!!!!
counter.increment()
})
.catch(error => console.log('error:', error));
};
这是一个常见问题,针对您的问题有很多解决方案。您需要将函数传递给 child,然后更新 parent。我将 link 回复我之前发布的一个答案。在你的情况下,你在哪里渲染
<Login upParentCounter={this.increment}/>
在登录组件内部
this.props.upParentCounter()
这个问题不是 Unstated 特有的,这也适用于使用 render prop 模式的 React 上下文 API。
login
的问题是它的控制流有缺陷。它无法有效地捕获错误,因为它会抑制错误。并且它把promise封装在里面,这是一个错误,阻止了它被正确测试,对于初学者来说
它可以暴露一个承诺,或者接受一个回调,或者两者兼而有之:
login = async (cb) => {
...
return axios(...)
.then(function(result) {
if (cb)
cb(result);
return result;
})
.catch(error => console.log('error:', error));
}
可用作:
<button onClick={() => login(() => counter.decrement())}>-</button>
或者:
<button onClick={async () => { await login(); counter.decrement(); }}>-</button>
也可以使 login
接受 counter
作为参数,但这会将其耦合到不必要的实现。