我正在尝试创建一个自定义钩子,它将为我们处理Aphrodite (https://github.com/Khan/aphrodite)样式的一些合并,但在传递样式对象时,我得到了一些不寻常的行为。
这是我的钩子:(这个计划是用useMemo编写的,这就是为什么它是一个钩子)
import castArray from 'lodash/castArray';
import {StyleSheet} from 'aphrodite';
import merge from 'lodash/merge';
export const useStyles = (styles, props) => {
return {
styles: StyleSheet.create(
[...castArray(styles), ...castArray(props.styles)]
.reduce((agg, next) => (merge(agg, next))),
)
};
};和基本用法:
function TestComponent(props) {
const {styles} = useStyles(baseStyles, props);
return <div className={css(styles.test)}>Test Text</div>
}如果传入一个styles支柱,它将与baseStyles中的任何内容合并,并为组件的这个实例提供一个最终的Aphrodite样式表。
我在这里创建了一个简单的repro存储库:https://github.com/bslinger/hooks-question
期望:在两条路径之间单击将改变文本的颜色,这取决于是否传递了道具以覆盖该样式。
实际:一旦样式被合并,即使没有附加道具的路线也会以覆盖的颜色显示出来。
注意:我意识到,在删除useMemo之后,这在技术上甚至不是一个钩子,降级对16.7的反应导致了同样的行为,所以我想这毕竟只是一个Javascript或React问题吧?
发布于 2019-02-12 05:02:06
这里的关键是详细了解Array.reduce的行为。reduce接受两个参数。第一个参数是您指定的回调。第二个参数是可选的,是累加器的初始值(回调的第一个参数)。以下是对这一论点的描述:
值作为回调的第一个调用的第一个参数。如果未提供初始值,则将使用数组中的第一个元素。在没有初始值的空数组上调用error ()是一个错误。
为了更容易地理解这一点的效果,它将有助于简化语法。
只要styles和props.styles不是数组(它们不在示例中),如下所示:
[...castArray(styles), ...castArray(props.styles)]相当于:
[styles, props.styles]因此,在没有initialValue对reduce函数的情况下,累加器将是数组中的第一个元素:styles。因此,一旦执行了"withProps“场景,就在styles.js中对对象进行了变异,没有任何东西会将其更改回原来的绿色。如果styles是一个数组(使用原始代码),那么该数组中的第一个样式对象就会出现这种副作用。
要解决这个问题,只需为累加器指定一个初始值:
export const useStyles = (styles, props) => {
return {
styles: StyleSheet.create(
[...castArray(styles), ...castArray(props.styles)].reduce(
(agg, next) => merge(agg, next),
{} // Here's an empty object as the accumulator initial value
)
)
};
};
https://stackoverflow.com/questions/54641308
复制相似问题