干掉反应代码。多个按钮组件,用于更改父组件的背景

时间:2018-02-02 19:55:52

标签: javascript css reactjs components dry

我确信有一种方法可以干掉代码。所有changeColor()正在做的是改变父组件的背景颜色。

import { Play } from "./play";
import { Hello } from "./hello";
import { styles } from "./styles";`

export class Buttons extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            color: styles.container
        };
        this.changeColor = this.changeColor.bind(this);
        this.changeColor1 = this.changeColor1.bind(this);
        this.changeColor2 = this.changeColor2.bind(this);
    }
    changeColor(newColor) {
        this.setState({
            color: styles.backPlay
        });
    }
    changeColor1(newColor) {
        this.setState({
            color: styles.backTime
        });
    }
    changeColor2(newColor) {
        this.setState({
            color: styles.backHello
        });
    }
    render() {
        return (
            <div style={this.state.color}>
                <Play onClick={this.changeColor} />
                <Time onClick={this.changeColor1} />
                <Hello onClick={this.changeColor2} />
            </div>
        );
    }
}

这是样式页面,我也认为可以使用一点DRY。 Container,backPlay,backTime和backHello都代表相同的容器,但背景不同。

styles.js

export var styles = {
    loc: {
        padding: 25,
        margin: 40,
        fontWeight: "bold",
        textAlign: "center"
    },
    green: {
        color: "green",
        background: "#59D13E"
    },
    red: {
        color: "yellow",
        background: "#A9A81D"
    },
    blue: {
        color: "blue",
        background: "#34BEE3"
    },
    container: {
        display: "inline-block",
        textAlign: "center",
        marginTop: 50,
        padding: 40

    },
    backPlay: {
        display: "inline-block",
        textAlign: "center",
        background: "yellow",
        marginTop: 50,
        padding: 40
    },
    backTime: {
        display: "inline-block",
        textAlign: "center",
        background: "blue",
        marginTop: 50,
        padding: 40
    },
    backHello: {
        display: "inline-block",
        textAlign: "center",
        background: "green",
        marginTop: 50,
        padding: 40
    },
    mainCont: {
        height: "100vh",
        textAlign: "center",
        background: "#FFA692"
    }
};

更新

我找到了更好的方法来干掉这段代码。通过使用一个按钮组件并操纵它的状态。如果有更好的方法可以告诉我。

ButtonContainer.js

import React from 'react'
import Button from './Button'

export default class ButtonContainer extends React.Component {
    state = {
        colors: ['red', 'blue', 'green']
    }
    toggleClass = (color, id) => {
        let colors = [...this.state.colors]
        const newColors = colors.map((newColor, index) => {
            if (id === index) {
                const copyMap = { 0: 'red', 1: 'blue', 2: 'green' }
                const copy = color === 'not' ? copyMap[index] : 'not'
                return copy
            } else {
                return newColor
            }
        })
        this.setState({ colors: newColors })
    }
    render() {
        return (
            <div className='button-container'>
                {this.state.colors.map((color, index) =>
                    <Button
                        toggleClass={this.toggleClass}
                        key={index}
                        id={index}
                        name={color}
                    />
                )}
            </div>
        )
    }
}

Button.js

import React from 'react'

const Button = (props) => (
    <button
        className={`button-component ${props.name}`}
        onClick={() => props.toggleClass(props.name, props.id)}
    >
        {props.name}
    </button>
)

export default Button

_button-container.scss

.button-container {
    margin: 10rem auto;
    text-align: center;
}

_button.scss

.button-component {
    padding: 4rem;
    margin: 0 2rem;
}

.red {
    background: red;
}

.blue {
    background: blue;
}

.green {
    background: green;
}

.not {
    background: none;
}

2 个答案:

答案 0 :(得分:2)

您可以使用.bind()预先绑定函数的参数,然后将其作为prop传递:

export class Buttons extends React.Component {
    state = {
        color: styles.container
    };
    changeColor = newColor => {
        this.setState({
            color: newColor
        });
    };
    render() {
        return (
            <div style={this.state.color}>
                <Play onClick={this.changeColor.bind(this, styles.backPlay)} />
                <Time onClick={this.changeColor.bind(this, styles.backTime)} />
                <Hello onClick={this.changeColor.bind(this, styles.backHello)} />
            </div>
        );
    }
}

您还可以删除构造函数并使用胖箭头函数将方法自动绑定到组件。

<强> styles.js

const container = {
    display: "inline-block",
    textAlign: "center",
    marginTop: 50,
    padding: 40
};

export const styles = {
    loc: {
        padding: 25,
        margin: 40,
        fontWeight: "bold",
        textAlign: "center"
    },
    green: {
        color: "green",
        background: "#59D13E"
    },
    red: {
        color: "yellow",
        background: "#A9A81D"
    },
    blue: {
        color: "blue",
        background: "#34BEE3"
    },
    container,
    backPlay: {
        ...container,
        background: "yellow"
    },
    backTime: {
        ...container,
        background: "blue"
    },
    backHello: {
        ...container,
        background: "green"
    },
    mainCont: {
        height: "100vh",
        textAlign: "center",
        background: "#FFA692"
    }
};

您可以使用es6 spread operatorstyles.container的内容复制到每个样式,然后覆盖color属性。

答案 1 :(得分:0)

由于您的所有颜色更改功能都非常相似,您可以传入要应用的样式名称并在功能中使用它,从而节省您的重复次数。

changeColor(attr) {
    this.setState({
        color: styles[attr]
    });
}

render() {
    return (
        <div style={this.state.color}>
            <Play onClick={() => this.changeColor('backPlay')} />
            <Time onClick={() => this.changeColor('backTime')} />
            <Hello onClick={() => this.changeColor('backHello')} />
        </div>
    );
}