有没有办法隐藏地将道具传递给组件?

时间:2016-06-21 02:26:36

标签: reactjs redux higher-order-functions

我希望能够为我的所有组件设置一个全局主题(变量集)来继承和扩展它们的默认变量。例如,我有一个button组件,其默认样式(内联CSS)引用了一组变量,例如primaryColor,...我希望能够更新这些变量很容易在我使用这些组件的任何地方,而无需将它们明确地传递给组件。

例如,我喜欢以下行为,我可以(1)将它们包装在一个组件中并让primaryColor级联到每个Button组件或(2)导出这个更高阶组件中的组件和feed更新道具等...但是,我无法使这些方法工作。也许,有更好的方法或......

(1)

render() {
  return (
    <Theme variables={{ 'primaryColor': 'red' }}>
      <Button />
      <SecondButton />
      <ThirdButton />
    </Theme>
  );
}

(2)

render() {
  return (
    <div>
      <Button />
      <SecondButton />
      <ThirdButton />
    </div>
  );
}

export default Theme(SampleComponent)

显然,这种方法可以正常传递给每个组件:

render() {
  return (
    <div>
      <Button variables={{ 'primaryColor': 'red' }} />
      <SecondButton variables={{ 'primaryColor': 'red' }} />
      <ThirdButton variables={{ 'primaryColor': 'red' }} />
    </div>
  );
}

3 个答案:

答案 0 :(得分:5)

我可以看到一些方法可以实现这一目标:

扩展儿童道具

有限,但允许通过&#39;额外&#39;用于指导组件子项的道具:

import React, { Component, Children } from 'react';

class Theme extends Component {
  getChildren () {
    const { children, variables } = this.props;
    // Clone the child components and extend their props
    return Children.map(children, (child) => React.cloneElement(child, {
      variables
    }));
  }

  render () {
    return Children.only(this.getChildren());
  }
}

// Example
<Theme variables={{ 'primaryColor': 'red' }}>
  <Button />
  <SecondButton />
  <ThirdButton />
</Theme>

反应上下文

将变量传递到React树的任何部分的最简单方法是使用React documentation中描述的上下文(这个确切的用例也是如此):

// Context provider
class ThemeProvider extends Component {
  getChildContext() {
    return {
      theme: this.props.variables
    };
  }

  render() {
    return Children.only(this.props.children);
  }
}

ThemeProvider.childContextTypes = {
  theme: PropTypes.object.isRequired
};

// HOC
function Theme(WrappedComponent) {
  class ThemeWrapper extends Component {

    render() {
      return <WrappedComponent { ...this.props } />;
    }
  }

  ThemeWrapper.contextTypes = {
    theme: PropTypes.object.isRequired
  };

  return ThemeWrapper;
};

// Using the HOC
class Button extends Component {
  render () {
    return <button style={{ color: this.context.theme.primaryColor }} />;
  }
}

const ThemeButton = Theme(Button);

// Example
<ThemeProvider variables={{ 'primaryColor': 'red' }}>
  <div>
    <ThemeButton />
  </div>
</ThemeProvider>

Redux商店

当您使用Redux时,您可以将需要以connect HOC为主题的每个组件包装起来,并将您的主题信息存储在商店状态中。这是一种共享数据的简单方法,可以避免上下文的复杂性:

class Button extends Component {
  render () {
    return <button style={{ color: this.props.theme.primaryColor }} />
  }
}

const ConnectedButton = connect((state) => ({ theme: state.theme }))(Button);

// Example
// During app setup
store.dispatch(setTheme({ 'primaryColor': 'red' }));

// Later
<div>
  <ConnectedButton />
</div>

希望这有帮助。

答案 1 :(得分:1)

对于任何来此发布后的人,here is an excellent guide都介绍了如何通过上下文和挂钩隐式传递道具。这篇文章的简短摘要:

ThemeContext.js:

const ThemeContext = React.createContext({});

export const ThemeProvider = ThemeContext.Provider;
export const ThemeConsumer = ThemeContext.Consumer;

export default ThemeContext;

HomePage.js:

import {ThemeProvider} from './ThemeContext.js';

const HomePage = () => {
  const handleClick = e => {};
  const currentTheme = {backgroundColor: 'black', color: 'white'};
  return (
    <ThemeProvider value={currentTheme}>
      <MyButton text='Click me!' onClick={handleClick} ... />
      ...
    </ThemeProvider>
  );
}

MyButton.js:

import React, { useContext } from 'react';
import ThemeContext from './ThemeContext';

const MyButton = ({text, onClick}) => {
  const style = useContext(ThemeContext);
  return <button style={style} onClick={onClick}>{text}</button>;
}

答案 2 :(得分:0)

如果您希望创建更高阶的组件,可以参考此http://gaearon.github.io/react-dnd/,但仍需要正确配置组件,以确定是否应该应用高阶组件的道具。< / p>

或者,为什么不创建一个包装组件,如myButton

export default class MyBytton(){
   render(){
     return <button { 'primaryColor': 'red' } />
   }
}

render(){
   return <MyButton otherProperty:"foo"/>
}