Skip to content

Blog Công Nghệ

MENUMENU
  • Trang chủ
  • Giới Thiệu
  • Lập Trình
    • Lập Trình Website
      • Laravel
        • Phân Tích Dự Án
      • PHP
      • SQL
      • HTML
      • CSS
      • Javascipt
      • My Project
      • Wordpress
    • Luyện Skill
    • Lập trình winform
    • CSDL
    • Lập Trình Android
    • Trí tuệ nhân tạo
    • Khai Khoáng Dữ Liệu
    • Arduino
    • Khác
    • Đồ án
  • Phần Mềm
    • Powerpoint
    • Tool
  • Cuộc sống và Giải trí
    • Hợp âm
    • web5ngay - youtube
    • Công Giáo
    • Kỹ Năng Sống
    • Street Workout
  • Danh sách bài viết
  • Guide line
    • Guild line phỏng vấn
    • Guide lines Laravel
    • Guide line Module Frontend
  • Tóm tắt sách
  • Fanpage

Blog Công Nghệ

Nơi chia sẻ kiến thức

Kinh nghiệm React

1 Tháng Mười Một, 2020 by admin
Lượt xem: 56

React là thư viện JavaScript phổ biến nhất để xây dựng giao diện người dùng (UI). Nó cho tốc độ phản hồi tuyệt vời khi user nhập liệu bằng cách sử dụng phương pháp mới để render trang web.

Contents

  • 1. Lộ trình học React
    • 1.1 Học React Class
    • 1.2 Học React Function sử dụng HOOK
    • 1.3 Material UI
    • 1.4 Kết hợp Laravel với React
    • 1.5 Validate form bằng redux-form và kết hợp react với redux
  • 2. Kinh nghiệm
    • 2.1 return
    • 2.2. if else
    • 2.3 style
    • 2.4 Thực hiện hành động nào đó sau khi gọi API
    • 2.5 Dấu …
    • 2.6 Redux
    • 2.7 Redux-form
      • 2.7.1 Quy trình
      • 2.7.2 Set giá trị cho form
        • Cách 1:
        • Cách 2:
        • Cách 3: (giống cách 2 nhưng chỉ sử dụng initialize)
      • 2.7.3 Sử dụng props của redux-form
      • 2.7.4 Thẻ form và handleSubmit
    • 2.8 Việc sử dụng, copy mảng, đối tượng
    • 2.9 Lỗi thiếu thư viện
    • 2.10 Plugin cho react
      • 2.10.1 Cách tìm kiếm google
      • 2.10.2 Các plugin react tổng hợp
  • 3. IDE Webstome
    • 3.1 Đi đến nhanh một component con
    • 3.2 Phát hiện các biến không sử dụng
  • 4. Theme Material
    • 4.1 Material Dashboard React
      • 4.1.1 Xóa sidebar lựa chọn theme
  • 5. Deploy lên server

1. Lộ trình học React

1.1 Học React Class

  1. Cài đặt môi trường
    Lưu ý: những chữ viết hoa. Mình từng viết React.Component chữ component mình không viết hoa và nó không chạy
//Để chạy dùng lệnh
npm start

2. Tìm hiểu về JSX

JSX khá giống với HTML

{1+1} // kết quả bằng 2
{/**/}  // để ghi chú

3. Tìm hiểu về các components trong React

State chứa biến trong component, hàm map như vòng lặp duyệt qua mảng

import React from 'react';

class App extends React.Component {
   constructor() {
      super();
      this.state = {
         data: 
         [
            {
               "id":1,
               "name":"Foo",
               "age":"20"
            },
            {
               "id":2,
               "name":"Bar",
               "age":"30"
            },
            {
               "id":3,
               "name":"Baz",
               "age":"40"
            }
         ]
      }
   }
   render() {
      return (
         <div>
            <Header/>
            <table>
               <tbody>
                  {this.state.data.map((person, i) => <TableRow key = {i} 
                     data = {person} />)}
               </tbody>
            </table>
         </div>
      );
   }
}
class Header extends React.Component {
   render() {
      return (
         <div>
            <h1>Header</h1>
         </div>
      );
   }
}
class TableRow extends React.Component {
   render() {
      return (
         <tr>
            <td>{this.props.data.id}</td>
            <td>{this.props.data.name}</td>
            <td>{this.props.data.age}</td>
         </tr>
      );
   }
}
export default App;

4. State

5. Props
Props để truyền biến từ component này sang component khác

6. component API

    • setState  => cập nhật state và khi state cập nhật sẽ render lại
    • forUpdate  => cập nhật và render lại
    • findDOMNode => lấy element chỉnh sửa
import React from 'react';
import ReactDOM from 'react-dom';

class App extends React.Component {
   constructor() {
      super();
      this.findDomNodeHandler = this.findDomNodeHandler.bind(this);
   };
   findDomNodeHandler() {
      var myDiv = document.getElementById('myDiv');
      ReactDOM.findDOMNode(myDiv).style.color = 'green';
   }
   render() {
      return (
         <div>
            <button onClick = {this.findDomNodeHandler}>FIND DOME NODE</button>
            <div id = "myDiv">NODE</div>
         </div>
      );
   }
}
export default App;

7. Vòng đời component

8. Form trong React

9. Event trong React

10. Refs

Refs giống như id trong HTML để lấy element nào đó làm những việc nào đó.

import React from 'react';
import ReactDOM from 'react-dom';

class App extends React.Component {
   constructor(props) {
      super(props);
  
      this.state = {
         data: ''
      }
      this.updateState = this.updateState.bind(this);
      this.clearInput = this.clearInput.bind(this);
   };
   updateState(e) {
      this.setState({data: e.target.value});
   }
   clearInput() {
      this.setState({data: ''});
      ReactDOM.findDOMNode(this.refs.myInput).focus();
   }
   render() {
      return (
         <div>
            <input value = {this.state.data} onChange = {this.updateState} 
               ref = "myInput"></input>
            <button onClick = {this.clearInput}>CLEAR</button>
            <h4>{this.state.data}</h4>
         </div>
      );
   }
}
export default App;

11. Key trong React

Key là định danh để chỉnh sửa element nhanh hơn

1.2 Học React Function sử dụng HOOK

  1. React Hook là gì và lợi ích
  2. Tìm hiểu các hook trong react
  3. useState trong React Hooks
import React, { useState } from 'react';

function Example() {
  // Khai báo một biến state mới, gọi nó là "count"
  const [count, setCount] = useState(0);
  
  return (
  );
}

1.3 Material UI

Trang web material ui

2 thư viện design khác:

  • Ant design: https://ant.design/
  • Style Component: https://styled-components.com/docs/basic
import React, {useState, useEffect} from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableContainer from '@material-ui/core/TableContainer';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import Paper from '@material-ui/core/Paper';



function createData(id, name, age) {
  return { id, name, age };
}



export default function DenseTable() {
  const [rows, setRow] = useState([
  							createData(1, 'Foo', 10),
    						createData(1, 'Bar', 20),
    						createData(1, 'Baz', 30)
  						]);

 
  //const classes = useStyles();

  const classes = {
    table: "minWidth: 650",
    w_300: {
      width: 300,
    },
    w_50: {
      width: 50,
    }
  };



  return (
      <TableContainer component={Paper} style={classes.w_300}>
        <Table className={classes.table} size="small" aria-label="a dense table">
          <TableHead>
            <TableRow>
              <TableCell style={classes.w_50}>id</TableCell>
              <TableCell align="left">Name</TableCell>
              <TableCell align="right">Age</TableCell>
            </TableRow>
          </TableHead>
          <TableBody>
            {rows.map((row) => (
              <TableRow key={row.name}>
                <TableCell component="th" scope="row">
                  {row.id}
                </TableCell>
                <TableCell align="left">{row.name}</TableCell>
                <TableCell align="right">{row.age}</TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>
      </TableContainer>
  );
}

1.4 Kết hợp Laravel với React

Đến đây mình khá bất ngờ, khi 2 công nghệ có thể kết hợp với nhau. Laravel làm backend và React làm frontend. Và mình biết được 2 công nghệ kết hợp với nhau thông qua API.

Đầu tiên các bạn cần tạo API bên Laravel theo bài viết này: https://code.tutsplus.com

Sau khi có API bên project React các bạn sử dụng fetch hoặc axios để lấy dữ liệu. https://reactjs.org/docs/faq-ajax.html

Lưu ý: khi bạn có dữ liệu và đổ lên state để sử dụng sẽ có một vòng lặp vô tận cứ chạy mãi, cứ gọi request phát sinh lỗi 429. Do đó bạn cần thêm tham số thứ 2 vào hàm useEffect() một mảng rỗng, để chỉ gọi request lần đầu tiên. Bạn tham khảo thêm bài viết https://topdev.vn

//code phía react
import React, {useState, useEffect} from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableContainer from '@material-ui/core/TableContainer';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import Paper from '@material-ui/core/Paper';



// function createData(id, name, age) {
//   return { id, name, age };
// }



export default function DenseTable() {
  const [rows, setRow] = useState([]);

  useEffect( () => {
    fetch("http://localhost/two_cn/server/api/data")
      .then(
          function(response) {
            if (response.status !== 200) {
              console.log('Lỗi, mã lỗi ' + response.status);
              return;
            }
            // parse response data
            response.json().then(data => {
              //console.log(data);
              setRow(data);
            })
          }
        )
        .catch(err => {
          console.log('Error :-S', err)
        });
  }, []);

  //const classes = useStyles();

  const classes = {
    table: "minWidth: 650",
    w_300: {
      width: 300,
    },
    w_50: {
      width: 50,
    }
  };



  

  return (
      <TableContainer component={Paper} style={classes.w_300}>
        <Table className={classes.table} size="small" aria-label="a dense table">
          <TableHead>
            <TableRow>
              <TableCell style={classes.w_50}>id</TableCell>
              <TableCell align="left">Name</TableCell>
              <TableCell align="right">Age</TableCell>
            </TableRow>
          </TableHead>
          <TableBody>
            {rows.map((row) => (
              <TableRow key={row.name}>
                <TableCell component="th" scope="row">
                  {row.id}
                </TableCell>
                <TableCell align="left">{row.name}</TableCell>
                <TableCell align="right">{row.age}</TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>
      </TableContainer>
  );
}

1.5 Validate form bằng redux-form và kết hợp react với redux

Bạn cần đọc các bải viết này để hiểu rõ nó:

  • Redux là gì? Hiểu rõ cơ bản cách dùng Redux
  • Cơ bản về redux-form:
    Bài viết này cho bạn cái nhìn đơn giản nhưng khá rõ về redux-form. Đồng thời có một ví dụ đơn giản theo từng quy trình tạo redux-form: Tạo Store => Tạo Form => Tạo Component <Field/> => Gọi form và xử lý submit
  • Bắt đầu với Redux? Tại sao Redux:
    Bài viết này là cái nhìn tổng quan và chi tiết về redux. Bao gồm tạo store, action, reducer. Bên cạnh đó là code ví dụ cho từng phần.
  • Redux Form Validate Tutorial:
    Đây là bài viết hướng dẫn tạo một redux-form hướng dẫn từ a-z. Bao gồm cả validate. Cũng khá là dễ hiểu và đơn giản.
  • Ví dụ đơn giản với react và redux tại phía client 
    Bài viết lại là một project làm bằng react và redux đơn giản. Nó là một quy trình của redux. Tạo các state dùng chung => Tạo reducer => tạo store với reducer => Truyền store => Sử dụng store tại component => component gọi action reducer

2. Kinh nghiệm

2.1 return

Return nhiều element chúng ta cần bọc nó với 1 container (div, …)

2.2. if else

Không thể sử dụng If Else trong JSX, thay vào đó sử dụng điều kiện rút gọn

import React from 'react';

class App extends React.Component {
   render() {
      var i = 1;
      return (
         <div>
            <h1>{i == 1 ? 'True!' : 'False'}</h1>
         </div>
      );
   }
}
export default App;

2.3 style

Bỏ vào một biến để sử dụng

import React from 'react';

class App extends React.Component {
   render() {
      var myStyle = {
         fontSize: 100,
         color: '#FF0000'
      }
      return (
         <div>
            <h1 style = {myStyle}>Header</h1>
         </div>
      );
   }
}
export default App;

2.4 Thực hiện hành động nào đó sau khi gọi API

const add_person = (person) => {
  console.log(person);
  axios.post('http://localhost/two_cn/server/api/data', person)
    .then(res => {
      console.log(res.data);
    });
}
 get_data();

Bạn đang bực bội mình viết gọi API rồi tới hàm mà sao nó cứ chạy hàm dưới trước rồi gọi API sau. Để giải quyết bạn phải sử dụng promise. Lúc này nó mới hiểu là gọi API xong mới xử lý.

const add_person = (person) => {
  console.log(person);
  axios.post('http://localhost/two_cn/server/api/data', person)
    .then(res => {
      console.log(res.data);
      get_data();
    });
}
// hàm get_data() sẽ thực hiện khi gọi API xong

Tham khảo thêm: Làm việc với asynchronous APIs

2.5 Dấu …

Ký tự gì lạ vậy trời. Đó là câu hỏi lúc đầu tôi mới bắt đầu học react. Thật ra nó chỉ là tách phần tử ra giúp mình thôi. (đúng hơn là copy mảng hoặc đối tượng)

Ví dụ bạn có mảng a = [5,6,7,8,9]

b = […a, 7]   => b = [5,6,7,8,9,7]

Tương tự với object.

Bạn tham khảo thêm tại 2 bài viết này nhé!

  • Spread operator (…) trong ES6

  • Giới thiệu Spread Operator của ES2015 (hay ES6)

2.6 Redux

Tạo defaultState

const defaultValue = {
	listUser: [],
}
const defaultState = defaultValue;

Tạo reducer

function reducerUser(state = defaultState, action) {
	switch (action.type) {
      case 'ADD':
        add_person(action.formData);
        return state;

       case 'SET_DATA':
        let users_data=[...action.data];
        return {...state, listUser:users_data};

        default:
        return state;
    }
    //return state;
}

Đăng ký rootReducer

const rootReducer = combineReducers({
    reducerUser,
    form: formReducer
});

Tạo store

const store = createStore(rootReducer);

Tạo provider

ReactDOM.render(
	<Provider store={store}>
	  <Router history={hist}>
	    <Switch>
	      <Route path="/admin" component={Admin} />
	      <Route path="/rtl" component={RTL} />
	      <Redirect from="/" to="/admin/dashboard" />
	    </Switch>
	  </Router>
	</Provider>,
  document.getElementById("root")
);

Sử dụng

function TableList = (props) {
 	const {listUser} = props; 
}


export default connect (function(state) {
  console.log("FROM VIEWER:", state); // in giá trị state
  return {
    listUser: state.reducerUser.listUser
  };
})(TableList);

Gọi action đến store

const add_person = (person) => {
  props.dispatch({
    type: 'ADD',
    formData: person
    });
}

2.7 Redux-form

2.7.1 Quy trình

Tạo store cho redux-form

const rootReducer = combineReducers({
    form: formReducer
});

const store = createStore(rootReducer);

Tạo form, Field của redux-form

const renderField = (props) => {
	const { input, label, type, meta: { touched, error, warning } } = props;
	return (
	<div>
	  <label className="control-label">{label}</label>
	  <div>
	    <input {...input} placeholder={label} type={type} className="form-control"/>
	    {touched && ((error && <span className="text-danger">{error}</span>) || (warning && <span>{warning}</span>))}
	  </div>
	</div>
	);
}

let Create = (props) => {
	/*--props--*/
	const { handleSubmit, pristine, reset, submitting } = props;

	/*--Variable--*/

	/*--state--*/
	const dataForm = props.dataForm;

	/*--method--*/
	const cancel = props.cancel;

	/**--style--*/
	
	return(
		<div>
			<form  onSubmit={ handleSubmit }>
			  <div className="form-group">
		        <Field name="name" component={renderField} label="Name"/>
		      </div>
		      <div className="form-group">
		        <Field name="age" component={renderField} label="Age"/>
		      </div>
			  <br />
			  <br />
			  <div className="form-group">
		        <button type="submit" className="btn btn-primary">Submit</button>
		        <Button style={{marginLeft: '10px'}} variant="contained" color="secondary" onClick={cancel}>
				  Hủy
			  	</Button>
		      </div>
			  
			</form>
		</div>
	);
}

tạo redux-form:

  • Tên form là duy nhất nhé
Create =  reduxForm({
  form: 'create', // a unique identifier for this form
  validate
})(Create)

Validate

const validate = values => {
    const errors = {}
    if (!values.name) {
      errors.name = 'Không được để trống'
    } else if (values.name.length < 2) {
      errors.name = 'Nhập ít nhất 2 ký tự'
    }
    if (!values.age) {
      errors.age = 'Không được để trống'
    } 
    
    return errors
  }

Gọi ra xài thôi

import React, {useState, useEffect, useCallback, updateState} from "react";
import ............

function LayoutCRUD(props) {

  const handleSubmitFormCreate = (person) => {
        .........
  }

  return (              
    <Create 
   		 onSubmit={handleSubmitFormCreate} 
    />
  );
}

(*)  Create truyền props onSubmit là props mặc định của redux-form cho phương thức submit. Ở Form tạo của redux-form sẽ sử dụng props này với tên là handleSubmit. Bạn lưu ý kỹ chỗ này nhé.

2.7.2 Set giá trị cho form

Tình huống:

  • Bạn nhấn nút thêm mới và muốn các trường trở về giá trị rỗng
  • Bạn nhấn nút chỉnh sửa và muốn đổ giá trị đó vào cho form

Khi mới tìm hiểu, mình bị bí chỗ này, mất cả tuần tìm hiểu không ra. Cảm thấy khá nãn, nhưng cuối cùng cũng thành công. Bạn làm theo bên dưới nhé.

Cách 1:

Ở file gọi redux-form của bạn bạn sẽ  truyền props data qua cho component chứa redux-form

import React, {useState, useEffect, useCallback, updateState} from "react";
import ............

function LayoutCRUD(props) {
  const [dataForm, setDataForm] = useState(personEmpty);
  
  const handleSubmitFormCreate = (person) => {
        .........
  }

  return (              
    <Create 
   		onSubmit={handleSubmitFormCreate} 
    	dataForm={dataForm}
    />
  );
}

component chứa redux-form, bạn nhận giá trị từ props này

let Create = (props) => {
	/*--props--*/
	const { handleSubmit, pristine, reset, submitting } = props;

	/*--state--*/
	const dataForm = props.dataForm;

	
	return(
		<div>
			<form  onSubmit={ handleSubmit }>
		        <Field name="name" component={renderField} label="Name"/>
		        <Field name="age" component={renderField} label="Age"/>
		        <button type="submit" className="btn btn-primary">Submit</button>
			</form>
		</div>
	);
}

Có data cho component rồi thì, set giá trị bằng cách viết vào function connect

  • Gồm connect và hàm mapStateToProps
let Create = (props) => {
	/*--props--*/
	const { handleSubmit, pristine, reset, submitting } = props;

	/*--state--*/
	const dataForm = props.dataForm;

	
	return(
		<div>
			<form  onSubmit={ handleSubmit }>
		        <Field name="name" component={renderField} label="Name"/>
		        <Field name="age" component={renderField} label="Age"/>
		        <button type="submit" className="btn btn-primary">Submit</button>
			</form>
		</div>
	);
}

const mapStateToProps = (state, props) => ({
  initialValues: props.dataForm, // retrieve name from redux store 
})

export default connect(
  mapStateToProps
)(reduxForm({
   form: 'simple', // a unique identifier for this form
  enableReinitialize: true
})(Create))
Cách 2:
  • add props initialized, initialize, change
  • Sử dụng trong useEffect nếu đã khỏi tạo => thay đổi giá trị ngược lại thì khởi tạo giá trị.
let TableCustom = (props) => {

  /*--props--*/
  const { handleSubmit, pristine, reset, submitting } = props;

  const {initialized, initialize, change} = props;

  const editRow = props.editRow;
  
  useEffect( () => { 
              if(initialized) {
                change("name", editRow.name); 
                change("age", editRow.age); 
              } else {
                initialize({...editRow});
              }
             }, 
         []);
  
    return (
      ...
    );
}
Cách 3: (giống cách 2 nhưng chỉ sử dụng initialize)
useEffect( () => { 
                initialize({...editRow});
             }, 
         []);

2.7.3 Sử dụng props của redux-form

Bạn sử dụng như ở mục 2.7.3 Cần xài cái nào thì bỏ vô như thế này:

const { handleSubmit, pristine, reset, submitting } = props;

const {initialized, initialize, change} = props;

Trang chủ redux-form có các props mà redux-form cung cấp: https://redux-form.com/

2.7.4 Thẻ form và handleSubmit

Thẻ form phải:

  • Bao cả Field và nút submit
<form  onSubmit={ handleSubmit }>
  <Field name="name" component={renderField} label="Name"/>
  <Field name="age" component={renderField} label="Age"/>
  <button type="submit" className="btn btn-primary">Submit</button>
</form>

Hoặc:

  • Chỉ bao quanh Field
  • button sẽ bắt sự kiện onClick và truyền vào props handleSubmit của redux-form
<form>
  <Field name="name" component={renderField} label="Name"/>
  <Field name="age" component={renderField} label="Age"/>
</form>
  
<button type="submit" className="btn btn-primary" onSubmit={handleSubmit}>Submit</button>

2.8 Việc sử dụng, copy mảng, đối tượng

Bạn nên sử dụng kí tự “…” để truyền mảng hoặc đối tượng vào (copy thành mảng, đối tượng khác), để tránh phát sinh lỗi. 

initialize({...editRow});

//thay vì:
initialize(editRow);

2.9 Lỗi thiếu thư viện

Kiểm tra file package.json có thư viện đó chưa? Nếu chưa:

  • tiến hành install
  • cài xong => npm start lại

2.10 Plugin cho react

2.10.1 Cách tìm kiếm google

Bạn search như sau:

  • vấn đề cần tìm + npm

Hoặc

  • vấn đề cần tìm + react

Tiêu chí chọn plugin:

  • Dễ cài đặt
  • Nhiều option để dễ tùy biến
  • Lượt tải nhiều

2.10.2 Các plugin react tổng hợp

  • Loading Data: react-spinner
  • Đọc HTML: react-html-parser  (code html => render ra , thường là CKEditor lưu dạng HTML)
  • Editor: 
  • Tag tab:

3. IDE Webstome

3.1 Đi đến nhanh một component con

ctrl + click

3.2 Phát hiện các biến không sử dụng

Sử dụng plugin … cho webstome IDE. 

4. Theme Material

4.1 Material Dashboard React

Link trang chủ theme: https://www.creative-tim.com

4.1.1 Xóa sidebar lựa chọn theme

Bạn vào Views/Layout/Admin.js

Tìm state FixedClass và bỏ chữ “show” đi.

Nếu muốn bỏ luôn bánh răng:

Bỏ luôn component <FixedPlugin> ở gần cuối file

5. Deploy lên server

Bạn chạy lệnh:

npm run build

Sau khi chạy xong,bạn vào thư mục public sẽ có 2 file dạng …app.js và …app.css

Bạn upload 2 file đó lên server là có thể chạy được.

Trường hợp có hình ảnh:

  • public/images: tất cả hình ảnh sẽ nằm trong đây
  • Bạn cũng upload folder này lên luôn nha.

Related posts:

  1. Kinh nghiệm ASP.NET + LINQ
  2. Kinh nghiệm DataTable
  3. Kinh nghiệm OpenCart
  4. Kinh nghiệm magento – mã nguồn mở PHP

Post navigation

Previous Post:

Kinh nghiệm magento – mã nguồn mở PHP

Next Post:

Khắc phục pin sạc không vào – báo lỗi “plugged in, not charging”

Trả lời Hủy

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *

Ẩn sidebar

Tìm kiếm

Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages

Blog Công Nghệ

Bài viết mới

  • Master typescript
  • Sendmail trong Laravel sử dụng dịch vụ SES, SQS của Amazon
  • Install SSL in Nginx Ubuntu
  • Docker study
  • Bảo vệ: Hướng dẫn code bot Telegram easy game

Lượng truy cập

0074501
Visit Today : 97
Visit Yesterday : 178
This Month : 772
Who's Online : 5
© 2025 Blog Công Nghệ | WordPress Theme by Superbthemes