需要完善的功能:
功能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的生命周期:
- React的生命周期只能定义在类组件中,不能定义在函数组件中;
- componentDidMount钩子函数,当页面刷新的时候执行;
- componentDidUpdate钩子函数,当页面渲染的时候执行;
- 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"));