在一个事件处理程序中拥有多个分派是一个好主意吗?

huangapple go评论59阅读模式
英文:

Is it a good idea to have many dispatches in one event handler?

问题

以下是您要翻译的内容:

"Could you explain if it is a good idea or not to put many dispatches on different actions in one click handler? Each dispatch has the function, which gets data from a JSON file and outputs the filtered array according to the value in the argument."

const handleBtnClick = () => {
        dispatch({
            type: ACTIONS_CITY.CONVERT_CITY_NAME,
            payload: convertCityNameToCoordinates(value) //finds a city name and returns coordinates of the city
        })                                               

        dispatch({
            type: ACTIONS_CITY.CHANGE_REGION,
            payload: getRegion(value) //finds a city name and return its region
        })

        dispatch({
            type: ACTIONS_CITY.CHANGE_POPULATION,
            payload: getPopulation(value) //return a population of provided city
        })
}

Reducer

export const cityReducer = (state, action) => {
    switch (action.type) {
        case (ACTIONS_CITY.CONVERT_CITY_NAME): {
            return {
                ...state,
                [state.cityCoordinates]: action.payload
            }
        }
        case (ACTIONS_CITY.CHANGE_POPULATION): {
            return {
                ...state,
                [state.population]: action.payload
            }

        }
        case (ACTIONS_CITY.CHANGE_REGION): {
            return {
                ...state,
                [state.region]: action.payload
            }
        }
        default:
            return state
    }
}
英文:

Could you explain if it is a good idea or not to put many dispatches on different actions in one click handler? Each dispatch has the function, which gets data from a JSON file and outputs the filtered array according to the value in the argument.

const handleBtnClick = () => {
        dispatch({
            type: ACTIONS_CITY.CONVERT_CITY_NAME,
            payload: convertCityNameToCoordinates(value) //finds a city name and returns coordinates of the city
        })                                               

        dispatch({
            type: ACTIONS_CITY.CHANGE_REGION,
            payload: getRegion(value) //finds a city name and return its region
        })

        dispatch({
            type: ACTIONS_CITY.CHANGE_POPULATION,
            payload: getPopulation(value) //return a population of provided city
        })
}

Reducer

export const cityReducer = (state, action) => {
    switch (action.type) {
        case (ACTIONS_CITY.CONVERT_CITY_NAME): {
            return {
                ...state,
                [state.cityCoordinates]: action.payload
            }
        }
        case (ACTIONS_CITY.CHANGE_POPULATION): {
            return {
                ...state,
                [state.population]: action.payload
            }

        }
        case (ACTIONS_CITY.CHANGE_REGION): {
            return {
                ...state,
                [state.region]: action.payload
            }
        }
        default:
            return state
    }
}

答案1

得分: 1

以下是翻译好的部分:

避免连续分派多个动作

避免连续分派多个动作以完成较大概念上的“事务”。 这是合法的,但通常会导致多次相对昂贵的UI更新,并且一些中间状态可能会被应用程序逻辑的其他部分视为无效。 更喜欢分派一个单一的“事件”类型动作,一次性导致所有适当的状态更新,或者考虑使用动作批处理插件以在最后一次UI更新时分派多个动作。

原因1. 多个状态更新导致多次渲染。

如果您正在使用React < 18版本并且在setTimeout()promise.then(resolveCallback)中连续分派多个动作,您应该使用react-redux中的batch() API,它在底层使用React.unstable_batchedUpdates() API,以允许在事件循环中的任何React更新一起批处理到单个渲染中。

由于handleBtnClick似乎是一个事件处理程序,您不需要使用batch() API。 React已经在其自己的事件处理程序回调中内部使用了这个功能。

原因2. 中间状态

此外,从概念上讲属于较大“事务”样式更新序列的多个分派将导致中间状态,这些中间状态可能不被视为有效。

如果我们可以一次更新状态,为什么要三次更新它呢?

改进的方法是使用带有所有三个有效负载的单个动作进行分派。

import React from 'react';

const ACTIONS_CITY = {
	CONVERT_CITY_NAME: 'CONVERT_CITY_NAME',
	CHANGE_POPULATION: 'CHANGE_POPULATION',
	CHANGE_REGION: 'CHANGE_REGION',
	CHANGE_CITY: 'CHANGE_CITY',
};

const cityReducer = (state, action) => {
	switch (action.type) {
		case ACTIONS_CITY.CHANGE_CITY: {
			return {
				...state,
				...action.payload,
			};
		}
		case ACTIONS_CITY.CONVERT_CITY_NAME: {
			return {
				...state,
				[state.cityCoordinates]: action.payload,
			};
		}
		case ACTIONS_CITY.CHANGE_POPULATION: {
			return {
				...state,
				[state.population]: action.payload,
			};
		}
		case ACTIONS_CITY.CHANGE_REGION: {
			return {
				...state,
				[state.region]: action.payload,
			};
		}
		default:
			return state;
	}
};

export default function App() {
	const [city, dispatch] = React.useReducer(cityReducer, { cityCoordinates: '100', population: 10000, region: 'japan' });
	console.log(city);
	const handleBtnClick = () => {
		dispatch({
			type: ACTIONS_CITY.CHANGE_CITY,
			payload: {
				cityCoordinates: '120',
				population: 20000,
				region: 'U.S',
			},
		});
	};

	return (
		<div className="App">
			<button onClick={handleBtnClick}>点击我</button>
		</div>
	);
}

CodeSandbox链接

更多阅读:我应该从一个动作创建器中连续分派多个动作吗?

英文:

One of the best practices is:

Avoid Dispatching Many Actions Sequentially

> Avoid dispatching many actions in a row to accomplish a larger conceptual "transaction". This is legal, but will usually result in multiple relatively expensive UI updates, and some of the intermediate states could be potentially invalid by other parts of the application logic. Prefer dispatching a single "event"-type action that results in all of the appropriate state updates at once, or consider use of action batching addons to dispatch multiple actions with only a single UI update at the end.

Reason 1. Multiple state updates cause multiple renders.

If you are using React <18 version and dispatch many actions sequentially in setTimeout(), promise.then(resolveCallback), you should use batch() API from react-redux which use React.unstable_batchedUpdates() API underly to allow any React updates in an event loop tick to be batched together into a single render pass.

Since handleBtnClick seems like an event handler, you don't need to use the batch() API. React already uses this internally for its own event handler callbacks.

Reason 2. Intermediate states

> In addition, multiple dispatches that are conceptually part of a larger "transaction"-style update sequence will result in intermediate states that might not be considered valid

If we can update the state once, why should we update it three times?

The way to improve is to dispatch a single action with all three payloads

import React from &#39;react&#39;;

const ACTIONS_CITY = {
	CONVERT_CITY_NAME: &#39;CONVERT_CITY_NAME&#39;,
	CHANGE_POPULATION: &#39;CHANGE_POPULATION&#39;,
	CHANGE_REGION: &#39;CHANGE_REGION&#39;,
	CHANGE_CITY: &#39;CHANGE_CITY&#39;,
};

const cityReducer = (state, action) =&gt; {
	switch (action.type) {
		case ACTIONS_CITY.CHANGE_CITY: {
			return {
				...state,
				...action.payload,
			};
		}
		case ACTIONS_CITY.CONVERT_CITY_NAME: {
			return {
				...state,
				[state.cityCoordinates]: action.payload,
			};
		}
		case ACTIONS_CITY.CHANGE_POPULATION: {
			return {
				...state,
				[state.population]: action.payload,
			};
		}
		case ACTIONS_CITY.CHANGE_REGION: {
			return {
				...state,
				[state.region]: action.payload,
			};
		}
		default:
			return state;
	}
};

export default function App() {
	const [city, dispatch] = React.useReducer(cityReducer, { cityCoordinates: &#39;100&#39;, population: 10000, region: &#39;japan&#39; });
	console.log(city);
	const handleBtnClick = () =&gt; {
		dispatch({
			type: ACTIONS_CITY.CHANGE_CITY,
			payload: {
				cityCoordinates: &#39;120&#39;,
				population: 20000,
				region: &#39;U.S&#39;,
			},
		});
	};

	return (
		&lt;div className=&quot;App&quot;&gt;
			&lt;button onClick={handleBtnClick}&gt;click me&lt;/button&gt;
		&lt;/div&gt;
	);
}

codesandbox

Further reading: Should I dispatch multiple actions in a row from one action creator?

huangapple
  • 本文由 发表于 2023年7月11日 03:11:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/76656655.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定