React从入门到项目 (第一篇)
Alex
简介:React是facebook(现在叫Meta)出的针对视图层的library库,目前最新版本18X
React官网- 点我去官网
通过这篇文章你会学到以下知识:
- 你将会学习到
- 如何创建和嵌套组件
- 如何添加标签和样式
- 如何显示数据
- 如何渲染条件和列表
- 如何对事件做出响应并更新界面
- 如何在组件间共享数据
1、首先我们在HML中使用react
我们需要准备三个东西
babel 作用是代码解析何jsx编译
react 核心库
react-dom 是在浏览器种使用react的必备插件
上面的第三方库 可以到NPM去下载(注意版本)
NPM-点我去NPM官网
2、JSX语法
简单描述:就是在js中直接写html标签
3、组件的定义和组件传参
React 中定义组建的方式有两种,
- function(函数式组件)
- class(类组件组件)
组件中的属性或者state数据改变之后 组件会重新渲染
3.1 入门React
- class定义的组件,类组件, 这种组件需要继承自Component类, 每一个class定义的组件需要一个render方法,这个方法需要一个返回值,返回的是当前组件的html代码
- 每一个function定义的组件都需要一个返回值,返回的内容表示组件的html标签, 每一个组件的最外层只能由一个跟节点
代码演示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>react入门使用</title>
</head>
<body>
<div id="app"></div>
<script src="./libs/babel.min.js"></script>
<script src="./libs/react.development.js"></script>
<script src="./libs/react-dom.development.js"></script>
<!-- 一定要加type,因为需要解析jsx语法内容 -->
<script type="text/babel">
// class定义的组件,类组件
// 这种组件需要继承自Component类
class Counter extends React.Component {
// 每一个class定义的组件需要一个render方法
// 这个方法需要一个返回值,返回的是当前组件的html代码
render() {
return (
<>
<button>我是一个计数器</button>
</>
);
}
}
const App = () => {
// 每一个function定义的组件都需要一个返回值,返回的内容表示组件的html标签
// 每一个组件的最外层只能由一个跟节点
return (
<>
<h1>这是一个react组件</h1>
<Counter />
</>
);
};
ReactDOM.render(<App />, document.querySelector("#app"));
</script>
</body>
</html>
3.2 组件的传参(函数组件)
父传子使用props,子传父,父组件传给子组件一个say方法,在子组件中调用say方法,传入给父组件的数据,在父组件的say方法的参数 可以拿到,简而言之就是'方法调用'
代码演示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>组件传参</title>
</head>
<body>
<div id="app"></div>
<script src="./libs/babel.min.js"></script>
<script src="./libs/react.development.js"></script>
<script src="./libs/react-dom.development.js"></script>
<script type="text/babel">
// 父传子 使用props属性
const Person = (props) => {
// console.log(props);
const { name, desc, say } = props;
const clickHandle = () => {
say(name); // 调用父组件的方法
};
// react中添加直接可以直接写,和原生一致,唯一的区别就是事件添加的时候使用小驼峰的方式命名
return (
<>
<h3>{name}</h3>
<p>{desc}</p>
<button onClick={clickHandle}>说</button>
<hr />
</>
);
};
const App = () => {
const people = [
{
id: 1,
name: "老白",
desc: "盗圣",
},
{
id: 2,
name: "吕轻侯",
desc: "关中大侠",
},
{
id: 3,
name: "老邢",
desc: "铺头",
},
{
id: 4,
name: "123",
desc: "小六的狗",
},
];
const say = (name) => {
alert(name);
};
return (
<>
<h1>这是一个组件</h1>
{people.map((item) => (
<Person key={item.id} {...item} say={say} />
))}
</>
);
};
ReactDOM.render(<App />, document.querySelector("#app"));
</script>
</body>
</html>
4、常用的Hooks(函数式组件)
在react16.8之前的版本中没办法在function定义的组件中设置局部状态,但是16.8之后的版本中新增了hooks,可以通过它为function定义组件设置局部状态和模拟生命周期。
hooks的实现原理是数组结合闭包
- useState
usesState可以在函数式组件中设置局部状态数据 ,
state数据改变之后组件重新渲染
setCount表示改变数据的方法
第一种方式,可以直接接收一个值,
第二种方式,可以接收一个function,这个function的返回值作为count的最新值,
function接收一个默认参数,表示sate数据的上一次的值
在类组件中不要在render的时候直接改变数据,会引起死循环
const [count,setCount] = React.useState(0)
<button onClick={() => setCount(count + 1)}>{count}</button>
<button onClick={() => setCount((c) => c + 2)}>{count}</button>
- useEffect
副作用,用来在function定义的组件中模拟组件的生命周期,
useEffect接收两个参数:
参数一:表示回调函数,
参数二:一个依赖数组
参数二有三种形式
- 参数二不存在,那么每一次组件更新的时候回调函数都会执行
- 参数二为空,那么参数一的回调函数在组件初始化的时候只执行一次(相当于componentDidMount)
- 参数二为数据的数组,那么参数一的回调函数在数组中的任意一个数据改变的时候执行。(相当于componentDidUpdate)
参数一中的回调函数可以返回一个function,这个返回的function在组件销毁的时候执行一次
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>useEffect</title>
</head>
<body>
<div id="app"></div>
<script src="./libs/babel.min.js"></script>
<script src="./libs/react.development.js"></script>
<script src="./libs/react-dom.development.js"></script>
<script type="text/babel">
const { useEffect, useState } = React;
const Ball = () => {
useEffect(() => {
// useEffect参数一的回调函数可以返回一个function,这个返回的方法在组件销毁的时候执行
return () => {
console.warn("组件销毁了");
};
}, []);
return (
<div
style={{ backgroundColor: "red", width: "100px", height: "100px" }}
/>
);
};
const App = () => {
const [count, setCount] = useState(0);
const [count1, setCount1] = useState(0);
const [count2, setCount2] = useState(0);
const [isShow, setIsShow] = useState(true);
useEffect(() => {
console.log("参数二为空数组,只执行一次");
}, []);
useEffect(() => {
console.log("count或者count1改变了");
}, [count, count1]);
useEffect(() => {
console.log("参数二不存在,每一次组件更新都执行");
});
return (
<>
<h1>
这是一个组件,count:{count},count1:{count1},count2:{count2}
</h1>
<button onClick={() => setCount(count + 1)}>count</button>
<button onClick={() => setCount1(count1 + 1)}>count1</button>
<button onClick={() => setCount2(count2 + 1)}>count2</button>
<hr />
<button
onClick={() => {
setIsShow(!isShow);
}}
>
toggle
</button>
{isShow ? <Ball /> : <p>啥都没有!</p>}
</>
);
};
ReactDOM.render(<App />, document.querySelector("#app"));
</script>
</body>
</html>
- useReducer
是react中另一种状态管理方案,使用的是单项数据流的机制,通过dispatch派发action改变数据,
useReducer 接收两个参数,参数一是一个reducer函数、参数二是一个初始状态数据;返回一个数组,数组的第一项是状态数据,第二项是dispath方法。如果要改变数据,只能通过dispatch派发一个action实现
每一个action需要包含一个type属性,用来标识数据改变的方式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>useReducer</title>
</head>
<body>
<div id="app"></div>
<script src="./libs/babel.min.js"></script>
<script src="./libs/react.development.js"></script>
<script src="./libs/react-dom.development.js"></script>
<script type="text/babel">
const { useReducer } = React;
const initState = {
count: 1,
list: [],
name: "小黑",
};
// 我们在reducer函数中改变数据的时候,根据action的type进行
const App = () => {
const [state, dispatch] = useReducer(function (state, action) {
console.group("reducer");
console.group("action");
console.log(action);
console.groupEnd();
console.group("state");
console.log(state);
console.groupEnd();
console.groupEnd();
switch (action.type) {
case "PLUS":
return { ...state, count: state.count + action.payload.step };
default:
return state;
}
// return state;
}, initState);
console.group("组件");
console.log(state);
console.log(dispatch);
console.groupEnd();
return (
<>
<h1>这是一个组件--{state.count}</h1>
<button
onClick={() => {
dispatch({
type: "PLUS",
payload: {
step: 1,
},
});
}}
>
count++
</button>
</>
);
};
ReactDOM.render(<App />, document.querySelector("#app"));
</script>
</body>
</html>
useReducer事例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>组件传参</title>
</head>
<body>
<div id="app"></div>
<script src="./libs/babel.min.js"></script>
<script src="./libs/react.development.js"></script>
<script src="./libs/react-dom.development.js"></script>
<script type="text/babel">
const { useReducer } = React;
// 以下的逻辑代码可以直接从组件中提取出来放在单独的文件进行管理,文件结构更清晰
const initState = {
list: [], // [{id: 1, name: '123', desc: ''}]
};
const listReducer = (state, { type, payload }) => {
switch (type) {
case "ADD":
return {
...state,
list: [...state.list, { id: Date.now(), ...payload }],
};
case "DEL":
return {
...state,
list: state.list.filter((item) => item.id != payload),
};
default:
return state;
}
};
const addAction = (data) => ({
type: "ADD",
payload: data,
});
// function addAction(data) {
// return {
// type: 'ADD',
// payload: data
// }
// }
const delAction = (id) => ({
type: "DEL",
payload: id,
});
const App = () => {
const [state, dispatch] = useReducer(listReducer, initState);
return (
<>
<input
type="text"
placeholder="请输入内容"
onKeyUp={(e) => {
if (e.keyCode === 13 && e.currentTarget.value) {
dispatch(addAction({ name: e.currentTarget.value }));
}
}}
/>
<hr />
<ul>
{state.list.map((item) => (
<li key={item.id}>
{item.name}
<button onClick={() => dispatch(delAction(item.id))}>
删除
</button>
</li>
))}
</ul>
</>
);
};
ReactDOM.render(<App />, document.querySelector("#app"));
</script>
</body>
</html>
- useContext
获取context上下文的参数
第一步:const context = React.createContext(); // 创建一个上下文
第二步:
ReactDOM.render(
<context.Provider value={{ s: “多重影分身” }}>
<App / >
</context.Provider>,
document.querySelector(“#app”)
);
第三步: const c = React.useContext(context);
代码演示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>useContext</title>
</head>
<body>
<div id="app"></div>
<script src="./libs/babel.min.js"></script>
<script src="./libs/react.development.js"></script>
<script src="./libs/react-dom.development.js"></script>
<script type="text/babel">
// Context上下文,可以实现跨组件之间传参
const context = React.createContext(); // 创建一个上下文
const YiDai = () => {
return (
<>
<h1>我是第一代目</h1>
<ErDai />
</>
);
};
const ErDai = () => {
return (
<>
<h2>我是第二代目</h2>
<SanDai />
</>
);
};
const SanDai = () => {
return (
<>
<h3>我是第三代目</h3>
<SiDai />
</>
);
};
const SiDai = () => {
// useContext这个hooks可以直接获取context上下文中的数据
const c = React.useContext(context);
console.log(c);
return (
<>
<h4>我是第四代目</h4>
<p>{c.s}</p>
<WuDai />
</>
);
};
const WuDai = () => {
return (
<>
<h5>我是第五代目</h5>
</>
);
};
const App = () => {
return (
<>
<h1>这是一个组件</h1>
<YiDai />
</>
);
};
// context.Provider是数据提供者,需要一个value属性 value表示可以让子组件消费(使用)的数据
ReactDOM.render(
<context.Provider value={{ s: "多重影分身" }}>
<App />
</context.Provider>,
document.querySelector("#app")
);
</script>
</body>
</html>
练习上下文传参
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>上下文传参练习</title>
</head>
<body>
<div id="app"></div>
<script src="./libs/babel.min.js"></script>
<script src="./libs/react.development.js"></script>
<script src="./libs/react-dom.development.js"></script>
<script type="text/babel">
const { createContext, useContext, useState } = React;
const context = createContext();
const AppProvider = ({ children }) => {
const [list, setList] = useState([]);
const add = (content) => {
setList([...list, { id: Date.now(), content, isEnd: false }]);
};
const end = (id) => {
setList(
list.map((item) =>
item.id == id ? { ...item, isEnd: true } : { ...item }
)
);
};
const del = (id) => {
setList(list.filter((item) => item.id != id));
};
return (
<context.Provider value={{ add, end, del, list }}>
{children}
</context.Provider>
);
};
// children属性,用来获取子节点
const Hello = ({ name, children, ...oo }) => {
console.log(name);
console.log(children);
console.log(oo);
return (
<>
<h1>{name}</h1>
{children}
</>
);
};
const TodoInput = () => {
const { add } = useContext(context);
const saveHandle = (e) => {
if (e.keyCode === 13 && e.currentTarget.value) {
add(e.currentTarget.value);
e.currentTarget.value = "";
}
};
return <input placeholder="请输入内容" onKeyUp={saveHandle} />;
};
const Todo = ({ id, content, isEnd }) => {
const { end, del } = useContext(context);
return (
<div>
<h3>{content}</h3>
{isEnd ? null : <button onClick={() => end(id)}>完成</button>}
<button
onClick={() => {
if (confirm("是否确认删除此项?")) del(id);
}}
>
删除
</button>
</div>
);
};
const Todos = () => {
const { list } = useContext(context);
return (
<>
{list.map((item) => (
<Todo key={item.id} {...item} />
))}
</>
);
};
const TodoList = () => {
return (
<>
<TodoInput />
<hr />
<Todos />
</>
);
};
const App = () => {
return (
<AppProvider>
<TodoList />
</AppProvider>
);
};
ReactDOM.render(<App />, document.querySelector("#app"));
</script>
</body>
</html>
- useRef
获取dom元素
- 受控组件和非受控组件
比如input输入框的值和state数据进行了绑定,这就是受控组件。
input输入框的值没有state数据进行绑定,在触发事件的时候通过dom元素获取值,那么就是非受控组件。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>useRef</title>
</head>
<body>
<div id="app"></div>
<script src="./libs/babel.min.js"></script>
<script src="./libs/react.development.js"></script>
<script src="./libs/react-dom.development.js"></script>
<script type="text/babel">
const { useRef, useState } = React;
const App = () => {
const iptUName = useRef(null);
const iptDesc = useRef(null);
const [txt, setTxt] = useState("");
return (
<>
<h1>这是一个组件</h1>
<ul>
<li>
<input ref={iptUName} type="text" placeholder="请输入昵称" />
</li>
<li>
<textarea ref={iptDesc} placeholder="请输入履历"></textarea>
</li>
<li>
<button
onClick={() => {
console.log(iptUName.current.value);
console.log(iptDesc.current.value);
}}
>
保存
</button>
</li>
</ul>
<hr />
<input
type="text"
placeholder="请输入内容"
onInput={(e) => {
setTxt(e.currentTarget.value);
}}
/>
</>
);
};
ReactDOM.render(<App />, document.querySelector("#app"));
</script>
</body>
</html>
- usecallback
作用是缓存一个function,接收两个参数,
参数一:是一个回调函数,
参数二:是一个依赖数组。建议多使用,做优化
const delHandle = React.useCallback((a) => {
// console.log(123);
console.log(a);
console.log(list); // 获取state数据的时候,取到的是初始数据
setList((data) => {
return data.filter((item) => item.id != a);
});
}, []); // 这个方法每一次组件渲染的时候都会重新生成
- useMemo
作用是缓存一个值,
参数一:一个回调函数
参数二:依赖数组
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>useMemo</title>
</head>
<body>
<div id="app"></div>
<script src="./libs/babel.min.js"></script>
<script src="./libs/react.development.js"></script>
<script src="./libs/react-dom.development.js"></script>
<script type="text/babel">
const { useState, useMemo } = React;
const App = () => {
const [count, setCount] = useState(0);
const [count1, setCount1] = useState(0);
const [count2, setCount2] = useState(0);
const [count3, setCount3] = useState(0);
const newC3 = useMemo(() => count3, [count1]);
return (
<>
<h1>这是一个组件</h1>
<p>
count: {count};count1: {count1};count2: {count2};count3:{" "}
{count3}
</p>
<p>最新的newC3:{newC3}</p>
<button onClick={() => setCount(count + 1)}>{count}</button>
<button onClick={() => setCount1(count1 + 1)}>{count1}</button>
<button onClick={() => setCount2(count2 + 1)}>{count2}</button>
<button onClick={() => setCount3(count3 + 1)}>{count3}</button>
</>
);
};
ReactDOM.render(<App />, document.querySelector("#app"));
</script>
</body>
</html>
- memo
用来对组件作用优化的时候使用,memo的作用是对组件做缓存,如果组件接收的属性不发改变,那么组件不会重新渲染。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>memo</title>
</head>
<body>
<div id="app"></div>
<script src="./libs/babel.min.js"></script>
<script src="./libs/react.development.js"></script>
<script src="./libs/react-dom.development.js"></script>
<script type="text/babel">
// memo的作用是对组件做缓存,如果组件接收的属性不发生改变,那么组件不会重新渲染
// memo 的作用是对组件做缓存,如果组件接收的属性不发生改变,那么组件不会重新渲染
const Item = ({ name, del, id }) => {
console.log("Item组件渲染了");
return (
<div>
<h3>{name}</h3>
<button onClick={() => del(id)}>{id}-删除</button>
</div>
);
};
const ItemMemo = React.memo(Item);
const App = () => {
const [list, setList] = React.useState([]);
const saveHandle = (e) => {
if (e.keyCode === 13 && e.currentTarget.value) {
setList([...list, { id: Date.now(), name: e.currentTarget.value }]);
}
};
const delHandle = React.useCallback((a) => {
// console.log(123);
console.log(a);
console.log(list); // 获取state数据的时候,取到的是初始数据
setList((data) => {
return data.filter((item) => item.id != a);
});
}, []); // 这个方法每一次组件渲染的时候都会重新生成
return (
<>
<input placeholder="请输入内容" onKeyUp={saveHandle} />
{list.map((item) => (
<ItemMemo
key={item.id}
name={item.name}
id={item.id}
del={delHandle}
/>
))}
</>
);
};
ReactDOM.render(<App />, document.querySelector("#app"));
</script>
</body>
</html>
5、练习 Todolist 、tabbar、加载更多等,
想要快速学会React,最重要的一点还是要多敲代码、多敲代码、多敲代码。重要的事情说三遍,
5.1 todolist 最基础版
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>TodoList</title>
</head>
<body>
<div id="app"></div>
<script src="./libs/babel.min.js"></script>
<script src="./libs/react.development.js"></script>
<script src="./libs/react-dom.development.js"></script>
<script type="text/babel">
const App = () => {
// [{id: 1, content: '', isEnd: false}]
const [list, setList] = React.useState([]);
const saveHandle = (e) => {
if (e.keyCode === 13) {
const content = e.currentTarget.value; // 定义一个变量存储数据
if (content) {
setList([
...list,
{
id: Date.now(),
content,
isEnd: false,
},
]);
e.currentTarget.value = "";
} else {
alert("请输入内容");
}
}
};
return (
<>
<input placeholder="请输入内容" onKeyUp={saveHandle} />
<hr />
{list.map((item) => (
<div className="item" key={item.id}>
<h3>{item.content}</h3>
{item.isEnd ? null : (
<button
onClick={() => {
setList(
list.map((todo) => {
if (item.id === todo.id) {
return {
...todo,
isEnd: true,
};
} else {
return todo;
}
})
);
}}
>
完成
</button>
)}
<button
onClick={() => {
setList(list.filter((todo) => todo.id != item.id));
}}
>
删除
</button>
<hr />
</div>
))}
</>
);
};
ReactDOM.render(<App />, document.querySelector("#app"));
</script>
</body>
</html>
5.2 tabbar
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>组件传参</title>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
/>
<style>
* {
padding: 0;
margin: 0;
}
li {
list-style: none;
}
.nav {
display: flex;
align-items: center;
justify-content: space-around;
box-shadow: 0 -1px 0 goldenrod;
}
.nav li {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: 0.8rem;
}
.nav li i {
font-size: 1.2rem;
}
.nav li.active {
color: deeppink;
}
</style>
</head>
<body>
<div id="app"></div>
<script src="./libs/babel.min.js"></script>
<script src="./libs/react.development.js"></script>
<script src="./libs/react-dom.development.js"></script>
<script type="text/babel">
const { useState } = React;
const TabBar = () => {
const [index, setIndex] = useState(0);
return (
<ul className="nav">
<li
className={index == 0 ? "active" : ""}
onClick={() => setIndex(0)}
>
<i className="fa fa-home"></i>首页
</li>
<li
className={index == 1 ? "active" : ""}
onClick={() => setIndex(1)}
>
<i className="fa fa-fire"></i>列表
</li>
<li
className={index == 2 ? "active" : ""}
onClick={() => setIndex(2)}
>
<i className="fa fa-shopping-cart"></i>购物车
</li>
<li
className={index == 3 ? "active" : ""}
onClick={() => setIndex(3)}
>
<i className="fa fa-user"></i>我的
</li>
</ul>
);
};
const App = () => {
return (
<>
<h1>这是一个组件</h1>
<TabBar />
</>
);
};
ReactDOM.render(<App />, document.querySelector("#app"));
</script>
</body>
</html>
5.3 加载更多
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>加载更多</title>
</head>
<body>
<div id="app"></div>
<script src="./libs/babel.min.js"></script>
<script src="./libs/react.development.js"></script>
<script src="./libs/react-dom.development.js"></script>
<script type="text/babel">
const { useState, useEffect } = React;
const App = () => {
const [page, setPage] = useState(1);
const [list, setList] = useState([]);
useEffect(() => {
// 调接口获取数据
fetch("http://localhost:1337/api/v1/products?page=" + page)
.then((res) => res.json())
.then((res) => {
setList([...list, ...res.data]);
});
}, [page]);
return (
<>
<ul>
{list.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
<button onClick={() => setPage(page + 1)}>加载更多</button>
</>
);
};
ReactDOM.render(<App />, document.querySelector("#app"));
</script>
</body>
</html>
5.4 获取数据播放
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>获取数据进行播放</title>
</head>
<body>
<div id="app"></div>
<script src="./libs/babel.min.js"></script>
<script src="./libs/react.development.js"></script>
<script src="./libs/react-dom.development.js"></script>
<script type="text/babel">
const { useState, useEffect } = React;
const App = () => {
// const [count, setCount] = useState(0); // 数据改变是异步的,获取最新的数据可以使用useEffect
// useEffect(() => {
// console.log(count);
// }, [count]);
const [songs, setSongs] = useState([]);
const [id, setId] = useState("");
const searchHandle = (e) => {
if (e.keyCode == 13 && e.currentTarget.value) {
// https://net-music.penkuoer.com/search?keywords=%E6%B5%B7%E9%98%94%E5%A4%A9%E7%A9%BA
fetch(
"https://net-music.penkuoer.com/search?keywords=" +
e.currentTarget.value
)
.then((res) => res.json())
.then((res) => {
setSongs(res.result.songs);
});
}
};
return (
<>
<input placeholder="请输入歌曲名字" onKeyUp={searchHandle} />
<hr />
<audio
autoplay
src={`https://music.163.com/song/media/outer/url?id=${id}.mp3`}
controls
></audio>
<ul>
{songs.map((item) => (
<li key={item.id} onClick={() => setId(item.id)}>
{item.name}
</li>
))}
</ul>
</>
);
};
ReactDOM.render(<App />, document.querySelector("#app"));
</script>
</body>
</html>
5.6 倒计时效果
当点了开始之后,按钮消失
同时页面开始倒计时10s,当倒计时到0的时候,显示一句话 活动已开始
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>1-倒计时效果</title>
</head>
<body>
<div id="app"></div>
<script src="./libs/babel.min.js"></script>
<script src="./libs/react.development.js"></script>
<script src="./libs/react-dom.development.js"></script>
<script type="text/babel">
const { useState, useEffect } = React;
const App = () => {
// 当点了开始之后,按钮消失
//同时 页面开始倒计时10s,当倒计时到0的时候,显示一句话 活动已开始
const [count, setCount] = useState(10);
const clickHandle = () => {
const timer = setInterval(() => {
console.log(count);
// setCount(count - 1);
setCount((c) => {
if (c == 1) clearInterval(timer);
return c - 1;
});
// if (count == 0) {
// clearInterval(timer); // 清除定时器
// }
}, 1000);
};
return (
<>
<h1>{count > 0 ? count : "活动已开始"}</h1>
<button onClick={clickHandle}>开始</button>
</>
);
};
ReactDOM.render(<App />, document.querySelector("#app"));
</script>
</body>
</html>
5.7 todolist组件版
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>todo-list-组件版</title>
</head>
<body>
<div id="app"></div>
<script src="./libs/babel.min.js"></script>
<script src="./libs/react.development.js"></script>
<script src="./libs/react-dom.development.js"></script>
<script type="text/babel">
const { useState } = React;
const TodoInput = ({ save }) => {
const saveHandle = (e) => {
if (e.keyCode === 13 && e.currentTarget.value) {
save(e.currentTarget.value);
e.currentTarget.value = "";
}
};
return <input placeholder="请输入内容" onKeyUp={saveHandle} />;
};
const Todo = ({ id, content, isEnd, end, del }) => {
return (
<div>
<h3>{content}</h3>
{isEnd ? null : <button onClick={() => end(id)}>完成</button>}
<button
onClick={() => {
if (confirm("是否确认删除此项?")) del(id);
}}
>
删除
</button>
</div>
);
};
const Todos = ({ list, end, del }) => {
return (
<>
{list.map((item) => (
<Todo key={item.id} {...item} end={end} del={del} />
))}
</>
);
};
const TodoList = () => {
const [list, setList] = useState([]);
// 保存
const save = (content) => {
setList([...list, { id: Date.now(), content, isEnd: false }]);
};
// 完成
const end = (id) => {
setList(
list.map((item) =>
item.id == id ? { ...item, isEnd: true } : { ...item }
)
);
};
// 删除
const del = (id) => setList(list.filter((item) => item.id != id));
return (
<>
<TodoInput save={save} />
<hr />
<Todos list={list} end={end} del={del} />
</>
);
};
const App = () => {
return (
<>
<TodoList />
</>
);
};
ReactDOM.render(<App />, document.querySelector("#app"));
</script>
</body>
</html>
5.8 自定义hooks
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>自定义hooks</title>
</head>
<body>
<div id="app"></div>
<script src="./libs/babel.min.js"></script>
<script src="./libs/react.development.js"></script>
<script src="./libs/react-dom.development.js"></script>
<script type="text/babel">
const { useState } = React;
// 自定义hooks
function useList() {
const [list, setList] = useState([]);
const add = (txt) => setList([...list, { id: Date.now(), txt }]);
const del = (id) => setList(list.filter((item) => item.id != id));
return {
list,
add,
del,
};
}
const App = () => {
const { list, add, del } = useList();
return (
<>
<input
placeholder="请输入内容"
onKeyUp={(e) => {
if (e.keyCode === 13 && e.currentTarget.value) {
add(e.currentTarget.value);
e.currentTarget.value = "";
}
}}
/>
<hr />
<ul>
{list.map((item) => (
<li key={item.id}>{item.txt}</li>
))}
</ul>
</>
);
};
ReactDOM.render(<App />, document.querySelector("#app"));
</script>
</body>
</html>