React 生命周期中的中间件如何工作?
How middleware in react life cycle works?
我是 React js 的新手。我已经开始用 react-redux 做一个小产品。我正在使用 saga 中间件。
我所做的如下。
这是组件
//all import work
import { activateAuthLayout, onLoad } from '../../../store/actions';
class EcommerceProductEdit extends Component {
constructor(props) {
super(props);
this.state = {
checked: false,
unselected_lists: [],
main_checked: false
}
//here I get the products props always null
console.log(this.props);
}
componentDidMount() {
this.props.activateAuthLayout();
//dispatching an action to fetch data from api, done in midddleware
if (this.props.user !== null && this.props.user.shop_id)
this.props.onLoad({
payload: this.props.user
});
}
render() {
//here I get the products props
console.log(this.props);
return (
//jsx work
);
}
}
const mapStatetoProps = state => {
const { user, is_logged_in } = state.Common;
const { products, is_loading } = state.Products;
return { user, is_logged_in, products, is_loading };
}
export default withRouter(connect(mapStatetoProps, { activateAuthLayout, onLoad })(EcommerceProductEdit));
行动是
import { FETCH_PRODUCT, FETCH_PRODUCT_SUCCESS } from './actionTypes';
export const onLoad = (action) => {
return {
type: FETCH_PRODUCT,
payload: action.payload
}
}
export const productFetched = (action) => {
return {
type: FETCH_PRODUCT_SUCCESS,
payload: action.payload
}
}
减速器是
import { FETCH_PRODUCT_SUCCESS } from './actionTypes';
const initialState = {
products: null,
is_loading: true
}
export default (state = initialState, action) => {
switch (action.type) {
case FETCH_PRODUCT_SUCCESS:
state = {
...state,
products: action.payload,
is_loading: false
}
break;
default:
state = { ...state };
break;
}
return state;
}
传奇是
import { takeEvery, put, call } from 'redux-saga/effects';
import { FETCH_PRODUCT } from './actionTypes';
import { productFetched } from './actions';
import agent from '../../agent';
function* fetchProduct(action) {
try {
let response = yield call(agent.Products.get, action.payload);
yield put(productFetched({ payload: response }));
} catch (error) {
if (error.message) {
console.log(error);
} else if (error.response.text === 'Unauthorized') {
console.log(error)
}
}
}
function* productSaga() {
yield takeEvery(FETCH_PRODUCT, fetchProduct)
}
export default productSaga;
我只能在渲染功能中获得产品道具。我怎样才能在构造函数中得到它?
如果有人向我解释更多有关 React 生命周期的信息,我将不胜感激。
谢谢。
已更新
你只需要安慰 props
而不是 this.props
。你不应该在构造函数中引用 props
和 this
。
改为这样做:
console.log(props)
中间件与 React 生命周期完全无关,除了它更新和连接的组件“反应”到 props 更新。
检查构造函数文档
https://reactjs.org/docs/react-component.html#constructor
问题:你为什么要尝试在构造函数中记录道具?如果您想知道道具是什么,请使用生命周期函数之一,componentDidMount
/componentDidUpdate
,不要使用渲染函数来产生副作用,例如进行异步调用或控制台日志。
componentDidMount() {
console.log(this.props);
}
如果您 必须 在构造函数中记录 props,访问作为组件传递的 props 对象还没有 this.props
填充。
constructor(props) {
super(props);
...
console.log(props);
}
在对象实例化期间调用构造函数。根据 docs“React 组件的构造函数在安装之前被调用”。因此,如果传递给组件的道具在安装组件后发生变化,您可以使用 componentWillReceiveProps
生命周期方法。
componentWillReceiveProps
已弃用,因此您可以改用 componentDidUpdate。来自文档的示例。
componentDidUpdate(prevProps) {
// Typical usage (don't forget to compare props):
if (this.props.userID !== prevProps.userID) {
// update your component state from here.
this.fetchData(this.props.userID);
}
}
MiddleWare: 中间件只是在动作被分派之后和它到达减速器之前出现在流程之间,就像你的情况一样,一旦你触发 onLoad 动作并且在它到达之前减速器,它被 Saga 中间件捕获,它根据其中编写的代码执行它
您案例中的生命周期如下:
在您的 compoenentDidMount 方法中,您发送了一个 onLoad 动作。这种情况下的动作类型变为“FETCH_PRODUCT”并且相同的动作现在在 Saga 中被捕获。
由于这是异步调用,因此组件中的代码会继续执行,而 Saga 会并行执行其操作。它通过这行代码调用 API : yield call(agent.Products.get, action.payload);
。一旦 API 调用完成,它会通过这行代码 yield put(productFetched({ payload: response }));
.
调度一个动作 'productfetched'
现在这个动作到达reducer并修改“products”的状态。由于您的 redux 中的产品状态已修改,因此您的组件 EcommerceProductEdit
会重新呈现,并且您会在 render 方法中获得产品列表。需要注意的是,此时流程必须已经在 componentDidMount 方法内部执行完毕,因此没有机会获得产品 their
您的问题的解决方法:
一旦一个动作被分派并且由于 Saga 而变得异步,如果你使用 Saga,你将无法在构造函数中获取值。您可以使用 componentDidMount 中的 axios/fetch 库直接调用 API 并等待它们(使其同步)。收到回复后,您可以继续下一步
如果你有功能组件,那么你可以使用 Effect hook 并将依赖项绑定到产品状态。您可以在此块中编写代码,在 API 调用和产品列表修改后要执行的代码。
React.useEffect(
() => {
// You code goes here
},
[products]
);
我是 React js 的新手。我已经开始用 react-redux 做一个小产品。我正在使用 saga 中间件。
我所做的如下。 这是组件
//all import work
import { activateAuthLayout, onLoad } from '../../../store/actions';
class EcommerceProductEdit extends Component {
constructor(props) {
super(props);
this.state = {
checked: false,
unselected_lists: [],
main_checked: false
}
//here I get the products props always null
console.log(this.props);
}
componentDidMount() {
this.props.activateAuthLayout();
//dispatching an action to fetch data from api, done in midddleware
if (this.props.user !== null && this.props.user.shop_id)
this.props.onLoad({
payload: this.props.user
});
}
render() {
//here I get the products props
console.log(this.props);
return (
//jsx work
);
}
}
const mapStatetoProps = state => {
const { user, is_logged_in } = state.Common;
const { products, is_loading } = state.Products;
return { user, is_logged_in, products, is_loading };
}
export default withRouter(connect(mapStatetoProps, { activateAuthLayout, onLoad })(EcommerceProductEdit));
行动是
import { FETCH_PRODUCT, FETCH_PRODUCT_SUCCESS } from './actionTypes';
export const onLoad = (action) => {
return {
type: FETCH_PRODUCT,
payload: action.payload
}
}
export const productFetched = (action) => {
return {
type: FETCH_PRODUCT_SUCCESS,
payload: action.payload
}
}
减速器是
import { FETCH_PRODUCT_SUCCESS } from './actionTypes';
const initialState = {
products: null,
is_loading: true
}
export default (state = initialState, action) => {
switch (action.type) {
case FETCH_PRODUCT_SUCCESS:
state = {
...state,
products: action.payload,
is_loading: false
}
break;
default:
state = { ...state };
break;
}
return state;
}
传奇是
import { takeEvery, put, call } from 'redux-saga/effects';
import { FETCH_PRODUCT } from './actionTypes';
import { productFetched } from './actions';
import agent from '../../agent';
function* fetchProduct(action) {
try {
let response = yield call(agent.Products.get, action.payload);
yield put(productFetched({ payload: response }));
} catch (error) {
if (error.message) {
console.log(error);
} else if (error.response.text === 'Unauthorized') {
console.log(error)
}
}
}
function* productSaga() {
yield takeEvery(FETCH_PRODUCT, fetchProduct)
}
export default productSaga;
我只能在渲染功能中获得产品道具。我怎样才能在构造函数中得到它? 如果有人向我解释更多有关 React 生命周期的信息,我将不胜感激。 谢谢。
已更新
你只需要安慰 props
而不是 this.props
。你不应该在构造函数中引用 props
和 this
。
改为这样做:
console.log(props)
中间件与 React 生命周期完全无关,除了它更新和连接的组件“反应”到 props 更新。
检查构造函数文档
https://reactjs.org/docs/react-component.html#constructor
问题:你为什么要尝试在构造函数中记录道具?如果您想知道道具是什么,请使用生命周期函数之一,componentDidMount
/componentDidUpdate
,不要使用渲染函数来产生副作用,例如进行异步调用或控制台日志。
componentDidMount() {
console.log(this.props);
}
如果您 必须 在构造函数中记录 props,访问作为组件传递的 props 对象还没有 this.props
填充。
constructor(props) {
super(props);
...
console.log(props);
}
在对象实例化期间调用构造函数。根据 docs“React 组件的构造函数在安装之前被调用”。因此,如果传递给组件的道具在安装组件后发生变化,您可以使用 componentWillReceiveProps
生命周期方法。
componentWillReceiveProps
已弃用,因此您可以改用 componentDidUpdate。来自文档的示例。
componentDidUpdate(prevProps) {
// Typical usage (don't forget to compare props):
if (this.props.userID !== prevProps.userID) {
// update your component state from here.
this.fetchData(this.props.userID);
}
}
MiddleWare: 中间件只是在动作被分派之后和它到达减速器之前出现在流程之间,就像你的情况一样,一旦你触发 onLoad 动作并且在它到达之前减速器,它被 Saga 中间件捕获,它根据其中编写的代码执行它
您案例中的生命周期如下:
在您的 compoenentDidMount 方法中,您发送了一个 onLoad 动作。这种情况下的动作类型变为“FETCH_PRODUCT”并且相同的动作现在在 Saga 中被捕获。
由于这是异步调用,因此组件中的代码会继续执行,而 Saga 会并行执行其操作。它通过这行代码调用 API :
调度一个动作 'productfetched'yield call(agent.Products.get, action.payload);
。一旦 API 调用完成,它会通过这行代码yield put(productFetched({ payload: response }));
.现在这个动作到达reducer并修改“products”的状态。由于您的 redux 中的产品状态已修改,因此您的组件
EcommerceProductEdit
会重新呈现,并且您会在 render 方法中获得产品列表。需要注意的是,此时流程必须已经在 componentDidMount 方法内部执行完毕,因此没有机会获得产品 their
您的问题的解决方法:
一旦一个动作被分派并且由于 Saga 而变得异步,如果你使用 Saga,你将无法在构造函数中获取值。您可以使用 componentDidMount 中的 axios/fetch 库直接调用 API 并等待它们(使其同步)。收到回复后,您可以继续下一步
如果你有功能组件,那么你可以使用 Effect hook 并将依赖项绑定到产品状态。您可以在此块中编写代码,在 API 调用和产品列表修改后要执行的代码。
React.useEffect( () => { // You code goes here }, [products] );