1.脚手架简介
- xxx脚手架: 用来帮助程序员快速创建一个基于xxx库的模板项目
- 包含了所有需要的配置(语法检查、jsx编译、devServer…)
- 下载好了所有相关的依赖
- 可以直接运行一个简单效果
- react提供了一个用于创建react项目的脚手架库: create-react-app
- 项目的整体技术架构为: react + webpack + es6 + eslint
- 使用脚手架开发的项目的特点: 模块化, 组件化, 工程化
2.脚手架搭建步骤
第一步,全局安装:npm i -g create-react-app
第二步,切换到想创项目的目录,使用命令:create-react-app hello-react
第三步,进入项目文件夹:cd hello-react
第四步,启动项目:npm start
第五步,Vscode 插件安装 ES7 React/Redux/GraphQL/React-Native snippets 代码模板插件,就可以输入rcc 直接填入类似组件模板代码。
3.脚手架文件夹作用
public ---- 静态资源文件夹
favicon.icon ------ 网站页签图标
index.html -------- 主页面。一般不用修改
logo192.png ------- logo图
logo512.png ------- logo图
manifest.json ----- 应用加壳的配置文件,用来将html转换为安卓、IOS等移动端程序的配置。
robots.txt -------- 爬虫协议文件
src ---- 源码文件夹
App.css -------- App组件的样式
App.js --------- App组件 ,一般用来引入自编写组件进行组合
App.test.js ---- 用于给App做测试
index.css ------ 样式
index.js ------- 入口文件 用来渲染组件到index.html
logo.svg ------- logo图
reportWebVitals.js
--- 页面性能分析文件(需要web-vitals库的支持)
setupTests.js
---- 组件单元测试的文件(需要jest-dom库的支持)
4.react项目结构
以下为目前公司常用的项目结构,方便、整洁。当然也不可以不如此安排目录
(1) 区分组件和普通js文件,一般采用如下两种方式
1)组件文件名首字母大写
2)组件文件的后缀为jsx
(2) src目录下增加components文件夹,用来存放组件,每个组件单独新建一个目录,然后存放此组件的css和js。
js文件命名为index,引入时不需要写具体文件名,直接写到文件夹就会自动寻找文件夹下面名为index.js的js文件
![]()
(3)index.js用来调用render渲染index的root容器
(4)App.js仅用来组合其他组件
(5)第三方的css放在public/css目录下,在index.html引入;第三方的js可以通过yarn安装,然后直接import即可;
(6)文件整体目录结构如下 index App直接放在src目录下 自写组件放在src/componnets目录以组件名命名的文件夹下,文件名为index.jsx 和index.css
5.补充:JavaScript的export和import
export有两种模块导出方式:命名式导出和默认导出,命名式导出每个模块可以多个,而默认导出每个模块仅一个。
(1 )命名式导出
基本语法。
name1
、name2
...nameN
可以是变量、函数或者类(合称为“内容”,下同)。导出的“标识符”。导出后,可以通过这个“标识符”在另一个模块中使用import引用
export { name1, name2, …, nameN };
别名。
variable1
是内容name1
的别名,外界可以通过别名访问到内容。其他以此类推
export { variable1 as name1, variable2 as name2, …, nameN };
定义内容的同时导出。
export let name1, name2, …, nameN; // also var export let name1 = …, name2 = …, …, nameN; // also var, const export function FunctionName(){...} export class ClassName {...}
(2)默认导出
export default expression; export default function (…) { … } // also class, function* export default function name1(…) { … } // also class, function* export { name1 as default, … };
- 默认导出。默认导出是可选的,但是如果有则必须唯一。
- default-设置模块的默认导出。设置后import不通过“标识符”而直接引用默认导入
import模块导入与export模块导出功能相对应,也存在两种模块导入方式:命名式导入(名称导入)和默认导入(定义式导入)。
(1) 命名式导入
我们可以通过指定名称,就是将这些成员插入到当作用域中,可以导入单个成员或多个成员:
注意:花括号里面的变量与export后面的变量一一对应
1.)import {myMember} from "my-module"; 2.)import {foo, bar} from "my-module";
通过*符号,我们可以导入模块中的全部属性和方法。当导入模块全部导出内容时,就是将导出模块('my-module.js')所有的导出绑定内容,插入到当前模块('myModule')的作用域中:
import * as myModule from "my-module";
(2)默认导入
在模块导出时,可能会存在默认导出。同样的,在导入时可以使用import指令导出这些默认值。
直接导入默认值:
import myDefault from "my-module";
也可以在命名空间导入和名称导入中,同时使用默认导入:
import myDefault, * as myModule from "my-module"; // myModule 做为命名空间使用 或 import myDefault, {foo, bar} from "my-module"; // 指定成员导入
6.项目主要编写文件目录
(1)index.js 入口文件,用来渲染组件
import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import App from './App'; import reportWebVitals from './reportWebVitals'; ReactDOM.render( <React.StrictMode> <App /> </React.StrictMode>, document.getElementById('root') );
(2)App.js 组合组件
import logo from './logo.svg';
import './App.css';
import Hello from './components/Hello'
function App() {
return (
<div className="App">
{/* 组合其他组件 */}
<Hello/>
</div>
);
}
export default App;
Webpack看来,一切皆模块。所以logo.svg这种图片亦可以直接import
7.精简项目 定制化开发
(1)删除脚手架构建项目的public、src文件夹下面所有文件
(2)public下面新建index.html文件 构建html页面结构
!!输入第一行的快捷键;div#root 快速新建id为root的div标签。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title>扩展</title> </head> <body> <div id="root"></div> </body> </html>
(3)src新建index.js App.js
index.js 让react使用App组件渲染html指定div
import React from 'react' import ReactDOM from 'react-dom' import App from './App' ReactDOM.render(<App/>,document.getElementById("root"))
App.js 组合各类组件 rcc快捷键新建类式组件。
import React, { Component } from 'react' export default class App extends Component { render() { return ( <div>App...</div> ) } }
(4)开发各种组件、组件路由。然后集成到App即可。 react最基本的框架搭建完成。
8.组件化开发步骤
功能界面的组件化编码流程(通用)
1. 拆分组件: 拆分界面,抽取组件
2. 实现静态组件: 使用组件实现静态页面效果
3. 实现动态组件
3.1 动态显示初始化数据
3.1.1 数据类型
3.1.2 数据名称
3.1.2 保存在哪个组件?
3.2 交互(从绑定事件监听开始)
9.开发示例
(1)实现效果
下面通过html+css代码实现了的静态页面效果,将其改变成react项目
(2)拆分组件: 拆分界面,抽取组件
约定:公司中常用
- react项目中,新建components文件夹用来存放组件。
- 每个组件新建一个文件夹放在components文件夹下,名字大写
- 组件内用index.jsx 和 index.css 给文件命名
(3)实现静态组件: 使用组件实现静态页面效果
css+html实现了静态页面效果,将html和css根据拆分成的组件进行代码拆分。将各个组件的css和标签放入组件文件夹中。
注意:
- jsx语法className代表类名
- jsx语法属性style={{display:"none"}},两个大括号包括的key value
- 每个标签都需要闭合标签 <input />等
- import顺序推荐:最上面import第三方js,然后自己写的组件,然后css文件
- 引入css文件 import './index.css' 需要指定引入文件的具体名称并加css后缀
- 引入js文件 省略js或者jsx后缀,webpack自动识别
(4)动态显示初始化数据
1.标签的事件函数可以选择接收event对象参数。此对象event.target表示标签本身,可以获取标签值等一些属性值;如果是onKeyUp事件,event.keyCode可以获取按键的编码值
2.react组件间传递参数 子组件向父组件传递参数
3.nanoid库 用来生成唯一的id;uuid库太大,所以不使用
npm i nanoid #安装的第三方库 直接from引入即可 直接去node_modules默认存三方库文件夹的查找 import {nanoid} from 'nanoid' nanoid() 调用方法产生唯一id
4.组件间传递参数
App组装组件用,是Header List Footer的父组件
父传参数到子组件(App->List)。爷孙节点也是通过props传递函数传递参数
<List todos={this.state.todos} />
子传参数到父组件
state和对其进行修改的方法要放在一个组件中。
(1)父组件定义操作自身state的函数通过props传给子组件 本项目中,父组件App定义一个函数传给子组件Header addTodos = (todoObj) => { const todos = [todoObj, ...this.state.todos] this.setState({ todos: todos }) } <Header addTodos={this.addTodos} /> (2)子组件调用父组件函数 将子组件数据传给父组件state addTodos=(event)=>{ const todo ={id:nanoid(),name:event.target.value,done:false} this.props.addTodos(todo) } <input type="text" onClick={this.addTodos} placeholder="请输入你的任务名称,按回车键确认" />
5.事件
- onKeyUp :按键起来以后调用
- ☑️复选框
<input type='checkbox' onChange={this.checkAll} checked='true'> 1)defaulChecked={done} 只根据done变量的值设置是否勾选;done变量变化后,就不再起作用。即仅第一次有用,以后不再有用 2)checked={done} done变量每次变化,勾选状态都会变化 3)onChange:复选框勾选发生变化调用
6.弹窗
- alert弹窗只有一个确定按钮
- window.confirm('确定删除吗') 会返回boolean类型值,有确定/取消两个按钮
7.reduce函数
arr.reduce(arg1,arg2)
- arg1为回调函数,接受两个参数 arg1(pre,cur) ,pre为回调函数上一次返回的值,cur为当前遍历到的元素的值
- arg2参数设置pre初始值;
let arr = [{done:false}{done:true}] //统计数组done为true的个数 arr.reduce((pre,cur)=>{ return pre + done? 1: 0 },0)
8.index.js 项目入口,调用render完成渲染;App.js为组合组件的js,即Footer、Header、List为其子组件,本项目将所有数据都存到App组件的state中。子组件通过App传过来的函数修改state值。 记住:state和对其进行修改的方法一定要放在一个组件中。
一、todoList案例相关知识点
1.拆分组件、实现静态组件,注意:className、style的写法
2.动态初始化列表,如何确定将数据放在哪个组件的state中?
——某个组件使用:放在其自身的state中
——某些组件使用:放在他们共同的父组件state中(官方称此操作为:状态提升)
3.关于父子之间通信:
- 【父组件】给【子组件】传递数据:通过props传递
- 【子组件】给【父组件】传递数据:通过props传递,要求父提前给子传递一个函数
- 注意defaultChecked 和 checked的区别,类似的还有:defaultValue 和 value
- 状态在哪里,操作状态的方法就在哪里