React 中使用 css
方式一:内联样式
render() {
return (
<>
<div style={
{
width: '100px', height: '100px', backgroundColor: 'pink'}}>react ts</div>
</>
)
}
方式二:外部样式
/* home.css */
.square{
width:100px;
height:100px;
background-color:pink;
}
.tsx 文件
import React, { Component } from 'react';
import './home.css';
...
render() {
return (
<>
<div className="square">react ts</div>
</>
)
}
需求:点击按钮更改样式
import React, {
Component } from 'react';
import './home.css';
interface IState {
width: number
}
class App extends Component<any, IState> {
constructor(props: any) {
super(props)
this.state = {
width: 200
}
}
change = () => {
this.setState((state) => ({
// width: 100 也一样
width: state.width - 100
}))
}
render() {
return (
<>
<div style={
{
width: `${
this.state.width}px`, height: '100px', backgroundColor: 'pink' }}>react ts</div>
<br />
<button onClick={
this.change}>改变宽度</button>
</>
)
}
}
export default App;
需求:当 div 的宽度小于 180px 就由正方形变圆形
import React, {
Component } from 'react';
import './home.css';
interface IState {
width: number
}
class App extends Component<any, IState> {
constructor(props: any) {
super(props)
this.state = {
width: 200
}
}
change = () => {
this.setState((state) => ({
// width: 100
width: state.width - 10
}))
}
render() {
return (
<>
<div className={
this.state.width > 180 ? 'square' : 'circle'}></div>
<br />
<button onClick={
this.change}>减少宽度</button>
</>
)
}
}
export default App;
/* home.css */
.square{
width:100px;
height:100px;
background-color:pink;
}
.circle{
width: 100px;
height: 100px;
background-color:pink;
border-radius: 50%;
}
封装列表删除按钮组件
子组件:
// DeleteUser.tsx
import {
Component } from 'react'
import {
Button } from 'antd'
interface IProps {
// 规定父组件要传的参数接口
id: number
callback: (id: number) => void
}
export default class DeleteUser extends Component<IProps, any> {
DeleteUser = () => {
// 发送网络请求,删除目标用户
this.props.callback(this.props.id) // 调用父组件传过来的方法,告诉被删除的 id,让父组件更新列表
}
render() {
return (
<>
<Button type="primary" danger onClick={
this.DeleteUser}>删除</Button>
</>
)
}
}
父组件:
import {
Component } from 'react';
import DeleteUser from './DeleteUser'
import 'antd/dist/antd.css'
import {
Button, Space, Table } from 'antd';
interface IUser {
id: number,
name: string
}
interface IState {
userList: IUser[]
}
class App extends Component<any, IState> {
constructor(props: any) {
super(props)
let tableList: IUser[] = []
for (let i = 0; i < 20; i++) {
tableList.push({
id: i,
name: 'user' + i
})
}
this.state = {
userList: tableList,
}
}
deleteUser = (id: number) => {
// 拿到子组件传过来的 id 做删除操作来更新列表数据
console.log(id)
this.setState(() => ({
userList: this.state.userList.filter(item => item.id !== id)
}))
}
render() {
return (
<>
<Table
dataSource={
this.state.userList}
rowKey='id'
>
<Table.Column title={
"ID"} dataIndex='id' />
<Table.Column title={
"姓名"} dataIndex='name' />
<Table.Column title={
"操作"} render={
(user: IUser) => (
<Space>
<Button type="primary" >编辑</Button>
<DeleteUser id={
user.id} callback={
this.deleteUser} />
</Space>
)} />
</Table>
</>
)
}
}
export default App;
组件状态提升,封装 Modal 组件
组件状态提升:子组件的属性交给父组件的状态去管理,父组件中的状态更新,就重新渲染子组件,更改子组件的某些状态
子组件:
import React, {
Component } from 'react'
import {
Modal } from 'antd'
interface IProps {
visible: boolean, // 子组件的 modal 显示与隐藏交给了父组的状态去管理,状态提升
title: string,
callback: (visible: boolean) => void
}
export default class EditModal extends Component<IProps, any> {
handleOk = () => {
// 编辑完用户信息发送网络请求
}
handleCancel = () => {
this.props.callback(false) // 告诉父组件要关闭了,传参之后具体关闭逻辑让父组件去实现
}
render() {
return (
<>
<Modal title={
this.props.title} visible={
this.props.visible} onOk={
this.handleOk} onCancel={
this.handleCancel}>
<p>Some contents...</p>
<p>Some contents...</p>
<p>Some contents...</p>
</Modal>
</>
)
}
}
父组件:
import {
Component } from 'react';
import EditModal from './EditModal';
import 'antd/dist/antd.css'
import {
Button, Space, Table } from 'antd';
interface IUser {
id: number,
name: string
}
interface IState {
userList: IUser[],
showEditModal: boolean
}
class App extends Component<any, IState> {
constructor(props: any) {
super(props)
let tableList: IUser[] = []
for (let i = 0; i < 20; i++) {
// 制造表格数据
tableList.push({
id: i,
name: 'user' + i
})
}
this.state = {
userList: tableList,
showEditModal: false
}
}
show = (visible: boolean) => {
this.setState(() => ({
showEditModal: visible
}))
}
render() {
return (
<>
<Table
dataSource={
this.state.userList}
rowKey='id'
>
<Table.Column title={
"ID"} dataIndex='id' />
<Table.Column title={
"姓名"} dataIndex='name' />
<Table.Column title={
"操作"} render={
(user: IUser) => (
<Space>
<Button type="primary" onClick={
() => {
this.show(true) }}>编辑</Button>
<EditModal visible={
this.state.showEditModal} title="编辑用户信息" callback={
this.show} />
</Space>
)} />
</Table>
</>
)
}
}
export default App;
高阶组件,参数为组件,返回值为新组件的函数
子组件
扫描二维码关注公众号,回复:
14738856 查看本文章
import {
Component } from 'react'
function Dog(Labrador: any, Corgi: any) {
// 返回值为新组件的函数被父组件渲染
return class extends Component<any, any>{
render() {
return (
<>
<div>
<h1>比熊犬</h1>
</div>
<Labrador />
<Corgi />
</>
)
}
}
}
class Labrador extends Component<any, any>{
render() {
return (
<>
<h1>拉布拉多</h1>
</>
)
}
}
class Corgi extends Component<any, any>{
render() {
return (
<>
<h1>柯基</h1>
</>
)
}
}
export default Dog(Labrador, Corgi) // 组件作为参数传给函数
父组件:
import {
Component } from 'react';
import Dog from './Dog';
import 'antd/dist/antd.css'
class App extends Component<any, any> {
render() {
return (
<>
<Dog />
</>
)
}
}
export default App;
Hooks + TS 做增加 TodoList 案例
组件划分
1、App 组件
2、TodoList 组件
3、子组件
- Input
- index
— List
- index
- Item
App.tsx
import {
Component } from 'react';
import TodoList from './components/Todolist'
import 'antd/dist/antd.css'
class App extends Component<any, any> {
render() {
return (
<>
<TodoList />
</>
)
}
}
export default App;
父组件 Todolist / index.tsx
import Input from './Input/index'
import TdList from './List'
import React, {
FC, ReactElement, useCallback, useEffect, useState } from 'react'
import {
ITodo } from './typings'
const TodoList: FC = (): ReactElement => {
const [todoList, setTodoList] = useState<ITodo[]>([])
useEffect(() => {
console.log(todoList)
}, [todoList])
const addTodo = useCallback(
(todo: ITodo) => {
setTodoList(todoList => [...todoList, todo])
}, [])
return (
<div>
<Input addTodo={
addTodo} todoList={
todoList} />
<TdList />
</div>
)
}
export default TodoList
Input / index.tsx
import React, {
FC, ReactElement, useRef } from 'react'
import {
ITodo } from '../typings/index';
interface IProps {
addTodo: (todo: ITodo) => void;
todoList: ITodo[]
}
const Input: FC<IProps> = ({
addTodo, todoList }): ReactElement => {
const inputRef = useRef<HTMLInputElement>(null)
const addItem = (): void => {
const val: string = inputRef.current!.value.trim() // 加 !断言 inputRef.current 一定不为 null
if (val.length) {
const isExist = todoList.find(item => item.content === val)
if (isExist) {
alert('已存在该项')
return
}
addTodo({
id: new Date().getTime(),
content: val,
completed: false
})
inputRef.current!.value = ''
}
}
return (
<div className="todo-input">
<input type="text" ref={
inputRef} placeholder="请输入待办项"></input>
<br />
<br />
<button onClick={
addItem}>增加</button>
</div>
)
}
export default Input
typings / index.tsx
export interface ITodo {
id: number;
content: string;
completed: false
}
interface 规范参数类型
import {
ReactNode } from 'react'
interface IMenu {
name: string
key: string | number
}
export interface IProfile {
name: string
icon: string
profile: string
intro: string
}
interface useVerificationOptions {
locale?: string
email?: string | number
currentCompany?: any
setHasSentEmailCode?: any
menus: IMenu[]
onChange?: (v: string | number) => void
handleAll: () => void
size?: 'small' | 'normal'
extra?: ReactNode
profile: IProfile // profile 为一个对象,里面的字段被 IProfile 接口约束
}
export function useVerification(props: useVerificationOptions) {
const {
locale, email, currentCompany, setHasSentEmailCode, menus, onChange, size= 'normal', handleAll } = props
......
}
enum SidePosition {
'left' = 'left',
'right' = 'right',
}
interface IPageLayoutProps {
side?: ReactNode
sidePosition?: SidePosition
wrapClassName?: string
}
// 拿到父组件传参的另一种形式
export const PageContent: FC<IPageLayoutProps> = ({
children,
side,
sidePosition = SidePosition.right,
wrapClassName,
}) => {
return (
<>
...
<main className="w-full xl:flex-1">{
children}</main>
</>
)
}
持续更新中…