09State详解

需要完善的功能:
功能1:删除单个Option
功能2:刷新后数据依旧存在

**功能1思路:**在option中添加一个button,然后绑定事件,点击的时候可以改变MyApp里的state的数组。所以我们应该把事件函数定义在MyApp中,通过传值给option。
传值过程: MyApp -> Options -> Option

class MyApp extends React.Component {
    constructor(props) {
        super(props);
        this.handleRemoveAll = this.handleRemoveAll.bind(this);
        this.handlePickOption = this.handlePickOption.bind(this);
        this.handleAddOption = this.handleAddOption.bind(this);
        this.state = {
            options: props.options
        }
    }
    handleAddOption(option) {
        // 验证
        if(!option) {
            return "选项不能为空"
        }else if(this.state.options.includes(option)) {
            return "不能输出重复的选项"
        }else {
            this.setState( prevState => ({ options: prevState.options.concat([option])}))
        }
    }
    handleRemoveOption() {
        console.log("回城...")
    }
    handleRemoveAll() {
        this.setState(() => ({options: []}))
    }
    handlePickOption() {
        const index = Math.floor(Math.random() * this.state.options.length);
        const option = this.state.options[index];
        alert(option)
    }
    render() {
        const title = "帮你决定ba";
        const subTitle = "把你的命交给电脑吧";
        return (
            <div>
                <Header subTitle={subTitle}/>
                <Action 
                    handleAddOption={this.handlePickOption}
                    hasOptions={this.state.options.length > 0} 
                    handlePickOption={this.handlePickOption}/>
                <Options 
                    options={this.state.options} 
                    handleRemoveAll={this.handleRemoveAll}
                    handleRemoveOption={this.handleRemoveOption}/>
                <AddOption handleAddOption={this.handleAddOption}/>
            </div>
        )
    }
}

MyApp.defaultProps = {
    options: ["鲁班7号", "小乔", "蔡文姬", "王昭君", "妲己", "安琪拉"]
}

// 小组件
const Header = (props) => {
    return (
        <div>
            <h1>{props.title}</h1>
            <p>{props.subTitle}</p>
        </div>
    )
}
Header.defaultProps = {
    title: "我就是默认值"
}

const Action = (props) => {
    return (
        <div>
            <button 
                onClick={props.handlePickOption}
                disabled={!props.hasOptions}
                >
                随机输出
            </button>
        </div>
    )
} 

const Options = (props) => {
    return (
        <div>
            <button onClick={props.handleRemoveAll}>重新开始</button>
            {props.options.map( (option, index) => (<Option key={index} option={option} handleRemoveOption={props.handleRemoveOption}/>))}
        </div>
    )
}

const Option = props => {
    return (
        <div>
            {props.option}
            <button onClick={props.handleRemoveOption}>击杀</button>
        </div>
    )
}

class AddOption extends React.Component {
    constructor(props) {
        super(props);
        this.formSubmit = this.formSubmit.bind(this);
        this.state = {
            error: undefined,
        }
    }
    formSubmit(e) {
        e.preventDefault();
        let option = e.target.elements.option.value.trim();
        const error = this.props.handleAddOption(option)
        console.log(error)
        this.setState( () => ({ error,}))
        e.target.elements.option.value = "";
    }
    render() {
        return (
            <div>
                {this.state.error && <p>{this.state.error}</p>}
                <form  onSubmit={this.formSubmit}>
                    <input type="text" name="option" placeholder="请输入要新增的英雄"/>
                    <button>新增英雄</button>
                </form>
            </div>
        )
    }
}

const User = (props) => {
    return (
        <div>
            <p>名字:{props.name}</p>
            <p>年龄:{props.age}</p>
        </div>
    )
}
ReactDOM.render(<MyApp/>, document.getElementById("app"));

在这里插入图片描述
按钮可以使用,继续完善功能:在点击的时候把对应的文本传回给事件函数,
点击的时候会执行函数,所以套一层函数,点击的时候把传参的那个函数写里面。

const Option = props => {
    return (
        <div>
            {props.option}
            <button onClick={() => {
                props.handleRemoveOption(props.option)
            }}>击杀</button>
        </div>
    )
}

在这里插入图片描述
然后在事件函数中开始使用setState来修改数组。

class MyApp extends React.Component {
    constructor(props) {
        super(props);
        this.handleRemoveAll = this.handleRemoveAll.bind(this);
        this.handlePickOption = this.handlePickOption.bind(this);
        this.handleAddOption = this.handleAddOption.bind(this);
        this.handleRemoveOption = this.handleRemoveOption.bind(this);
        this.state = {
            options: props.options
        }
    }
    handleAddOption(option) {
        // 验证
        if(!option) {
            return "选项不能为空"
        }else if(this.state.options.includes(option)) {
            return "不能输出重复的选项"
        }else {
            this.setState( prevState => ({ options: prevState.options.concat([option])}))
        }
    }
    handleRemoveOption(option) {
        this.setState( prevState => ({
            // 让他直接return对象,而不是代码块
            options: prevState.options.filter((item) => {
                return item !== option
            })
            // console.log(option)
            // 拿到上一个数组
            // 注意不能改变原数组的内存
            // 筛选
        }))
    }
    handleRemoveAll() {
        this.setState(() => ({options: []}))
    }
    handlePickOption() {
        const index = Math.floor(Math.random() * this.state.options.length);
        const option = this.state.options[index];
        alert(option)
    }
    render() {
        const title = "帮你决定ba";
        const subTitle = "把你的命交给电脑吧";
        return (
            <div>
                <Header subTitle={subTitle}/>
                <Action 
                    handleAddOption={this.handlePickOption}
                    hasOptions={this.state.options.length > 0} 
                    handlePickOption={this.handlePickOption}/>
                <Options 
                    options={this.state.options} 
                    handleRemoveAll={this.handleRemoveAll}
                    handleRemoveOption={this.handleRemoveOption}/>
                <AddOption handleAddOption={this.handleAddOption}/>
            </div>
        )
    }
}

MyApp.defaultProps = {
    options: ["鲁班7号", "小乔", "蔡文姬", "王昭君", "妲己", "安琪拉"]
}

// 小组件
const Header = (props) => {
    return (
        <div>
            <h1>{props.title}</h1>
            <p>{props.subTitle}</p>
        </div>
    )
}
Header.defaultProps = {
    title: "我就是默认值"
}

const Action = (props) => {
    return (
        <div>
            <button 
                onClick={props.handlePickOption}
                disabled={!props.hasOptions}
                >
                随机输出
            </button>
        </div>
    )
} 

const Options = (props) => {
    return (
        <div>
            <button onClick={props.handleRemoveAll}>重新开始</button>
            {props.options.map( (option, index) => (<Option key={index} option={option} handleRemoveOption={props.handleRemoveOption}/>))}
        </div>
    )
}

const Option = props => {
    return (
        <div>
            {props.option}
            <button onClick={() => {
                props.handleRemoveOption(props.option)
            }}>击杀</button>
        </div>
    )
}

class AddOption extends React.Component {
    constructor(props) {
        super(props);
        this.formSubmit = this.formSubmit.bind(this);
        this.state = {
            error: undefined,
        }
    }
    formSubmit(e) {
        e.preventDefault();
        let option = e.target.elements.option.value.trim();
        const error = this.props.handleAddOption(option)
        console.log(error)
        this.setState( () => ({ error,}))
        e.target.elements.option.value = "";
    }
    render() {
        return (
            <div>
                {this.state.error && <p>{this.state.error}</p>}
                <form  onSubmit={this.formSubmit}>
                    <input type="text" name="option" placeholder="请输入要新增的英雄"/>
                    <button>新增英雄</button>
                </form>
            </div>
        )
    }
}

const User = (props) => {
    return (
        <div>
            <p>名字:{props.name}</p>
            <p>年龄:{props.age}</p>
        </div>
    )
}
ReactDOM.render(<MyApp/>, document.getElementById("app"));

功能1完成:
在这里插入图片描述

功能2思路:
原本是当刷新的时候向后台请求一下数据,新增或离开的时候向后台提交数据。但是我们是前端,没法用后端,所以使用localStorage来存储。
了解一下React的生命周期:

  1. React的生命周期只能定义在类组件中,不能定义在函数组件中;
  2. componentDidMount钩子函数,当页面刷新的时候执行;
  3. componentDidUpdate钩子函数,当页面渲染的时候执行;
  4. componentWillUnmount稿子函数,当页面卸载的时候执行。
    componentDidMount() {
        console.log("刷新页面")
    }
    componentDidUpdate() {
        console.log("渲染页面")
    }

在这里插入图片描述

componentWillUnmount() {
        console.log("卸载页面")
    }

在这里插入图片描述
React的生命周期不止这三个钩子函数,当时常用的只有这三个,具体看官网文档。

localStorage部分:
存储数据:

componentDidUpdate(prevProps, prevState) {
        // 只有上一个数据和这一个数据发生改变的时候才能存储数据,不然空数组多次存储,有点浪费。
        if(this.state.options.length !== prevState.options.length) {
            const json = JSON.stringify(this.state.options);
            localStorage.setItem("options", json)
        }
    }

在这里插入图片描述
读取数据:

componentDidMount() {
        console.log("刷新页面")
        const json = localStorage.getItem("options");
        const options = JSON.parse(json);
        // 判断是否有option
        if(options) {
            this.setState(() => ({
                options
            }))
            // return对象
        }
    }

在这里插入图片描述
其他功能:当没有一个英雄的时候提示请添加第一个英雄。

const Options = (props) => {
    return (
        <div>
            <button onClick={props.handleRemoveAll}>重新开始</button>
            {props.options.length === 0 && <p>请添加你的第一个英雄:</p>}
            {props.options.map( (option, index) => (<Option key={index} option={option} handleRemoveOption={props.handleRemoveOption}/>))}
        </div>
    )
}

在这里插入图片描述
完整代码:

class MyApp extends React.Component {
    constructor(props) {
        super(props);
        this.handleRemoveAll = this.handleRemoveAll.bind(this);
        this.handlePickOption = this.handlePickOption.bind(this);
        this.handleAddOption = this.handleAddOption.bind(this);
        this.handleRemoveOption = this.handleRemoveOption.bind(this);
        this.state = {
            options: props.options
        }
    }
    componentDidMount() {
        console.log("刷新页面")
        // try catch防止数据被篡改报错 不合法的json格式
        try{
            const json = localStorage.getItem("options");
            const options = JSON.parse(json);
            // 判断是否有option
            if(options) {
                this.setState(() => ({
                    options
                }))
                // return对象
            }
        }catch(e){
            // 什么都不做
        }
        
    }
    componentDidUpdate(prevProps, prevState) {
        // 只有上一个数据和这一个数据发生改变的时候才能存储数据,不然空数组多次存储,有点浪费。
        if(this.state.options.length !== prevState.options.length) {
            const json = JSON.stringify(this.state.options);
            localStorage.setItem("options", json)
        }
    }
    componentWillUnmount() {
        console.log("卸载页面")
    }
    handleAddOption(option) {
        // 验证
        if(!option) {
            return "选项不能为空"
        }else if(this.state.options.includes(option)) {
            return "不能输出重复的选项"
        }else {
            this.setState( prevState => ({ options: prevState.options.concat([option])}))
        }
    }
    handleRemoveOption(option) {
        this.setState( prevState => ({
            // 让他直接return对象,而不是代码块
            options: prevState.options.filter((item) => {
                return item !== option
            })
            // console.log(option)
            // 拿到上一个数组
            // 注意不能改变原数组的内存
            // 筛选
        }))
    }
    handleRemoveAll() {
        this.setState(() => ({options: []}))
    }
    handlePickOption() {
        const index = Math.floor(Math.random() * this.state.options.length);
        const option = this.state.options[index];
        alert(option)
    }
    render() {
        const title = "帮你决定ba";
        const subTitle = "把你的命交给电脑吧";
        return (
            <div>
                <Header subTitle={subTitle}/>
                <Action 
                    handleAddOption={this.handlePickOption}
                    hasOptions={this.state.options.length > 0} 
                    handlePickOption={this.handlePickOption}/>
                <Options 
                    options={this.state.options} 
                    handleRemoveAll={this.handleRemoveAll}
                    handleRemoveOption={this.handleRemoveOption}/>
                <AddOption handleAddOption={this.handleAddOption}/>
            </div>
        )
    }
}

MyApp.defaultProps = {
    options: ["鲁班7号", "小乔", "蔡文姬", "王昭君", "妲己", "安琪拉"]
}

// 小组件
const Header = (props) => {
    return (
        <div>
            <h1>{props.title}</h1>
            <p>{props.subTitle}</p>
        </div>
    )
}
Header.defaultProps = {
    title: "我就是默认值"
}

const Action = (props) => {
    return (
        <div>
            <button 
                onClick={props.handlePickOption}
                disabled={!props.hasOptions}
                >
                随机输出
            </button>
        </div>
    )
} 

const Options = (props) => {
    return (
        <div>
            <button onClick={props.handleRemoveAll}>重新开始</button>
            {props.options.length === 0 && <p>请添加你的第一个英雄:</p>}
            {props.options.map( (option, index) => (<Option key={index} option={option} handleRemoveOption={props.handleRemoveOption}/>))}
        </div>
    )
}

const Option = props => {
    return (
        <div>
            {props.option}
            <button onClick={() => {
                props.handleRemoveOption(props.option)
            }}>击杀</button>
        </div>
    )
}

class AddOption extends React.Component {
    constructor(props) {
        super(props);
        this.formSubmit = this.formSubmit.bind(this);
        this.state = {
            error: undefined,
        }
    }
    formSubmit(e) {
        e.preventDefault();
        let option = e.target.elements.option.value.trim();
        const error = this.props.handleAddOption(option)
        console.log(error)
        this.setState( () => ({ error,}))
        e.target.elements.option.value = "";
    }
    render() {
        return (
            <div>
                {this.state.error && <p>{this.state.error}</p>}
                <form  onSubmit={this.formSubmit}>
                    <input type="text" name="option" placeholder="请输入要新增的英雄"/>
                    <button>新增英雄</button>
                </form>
            </div>
        )
    }
}

const User = (props) => {
    return (
        <div>
            <p>名字:{props.name}</p>
            <p>年龄:{props.age}</p>
        </div>
    )
}
ReactDOM.render(<MyApp/>, document.getElementById("app"));
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值