React JS
https://react.dev/learn/start-a-new-react-project
npx create-next-app@latest
npx create-react-app@latest {project name}
Create Project
C:\react-js>npx create-react-app@latest my-app
Run
C:\react-js\my-app> npm start
Install tailwindcss https://tailwindcss.com/docs/guides/create-react-app
npm install -D tailwindcss
npx tailwindcss
init Install
react-router-dom
https://www.npmjs.com/package/react-router-dom Install axios
src\App.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | //src\App.js import { BrowserRouter, Routes, Route } from "react-router-dom" ; //npm i react-router-dom https://www.npmjs.com/package/react-router-dom import Home from "./elements/Home" ; import ViewPage from "./elements/ViewPage" ; function App() { return ( <BrowserRouter> <Routes> <Route path= "/" element={<Home />} /> <Route path= "/posts/:slug" element={<ViewPage />} /> </Routes> </BrowserRouter> ); } export default App; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | //src\elements\Home.js import React from 'react' ; import Posts from './Posts' import { Suspense } from "react" ; import { IoSearch } from "react-icons/io5" ; //https://www.npmjs.com/package/react-icons npm install react-icons --save function Home() { return ( <div className= "w-screen py-20 flex justify-center flex-col items-center" > <div className= "flex items-center justify-between gap-1 mb-5" > <h1 className= "text-4xl font-bold" >React.js + WordPress Load Posts with Featured Image and View Single Page | Tailwind CSS</h1> </div> <div className= "overflow-x-auto py-10" > <div className= "mb-2 w-full text-right" > <div className= "relative flex flex-1" > <input type= "text" className= "w-full border border-gray-200 py-2 pl-10 text-sm outline-2 rounded-sm" placeholder= "Search..." /> <IoSearch className= "absolute left-3 top-2 h-5 w-5 text-gray-500" /> </div> </div> <Suspense fallback= "Loading..." > <Posts/> </Suspense> </div> </div> ) } export default Home |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | //src\elements\Posts.js import React, { useEffect, useState } from 'react' ; export default function Posts() { const [posts, setPosts] = useState([]); useEffect(() => { async function loadPosts() { if (!response.ok) { // oups! something went wrong return ; } const posts = await response.json(); setPosts(posts); } loadPosts(); }, []) return ( <div className= "grid md:grid-cols-3 gap-5 mt-10" > {posts.map((post, index) => ( <div key={index} className= "max-w-sm border border-gray-200 rounded-md shadow" > <div className= "relative aspect-video" > <img src={post._embedded[ "wp:featuredmedia" ][0].media_details.sizes.full.source_url} alt={post.title.rendered} fill priority sizes= "(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw" className= "rounded-t-md object-cover" /> </div> <div className= "p-5" > <h1> <a href={`/posts/${post.slug}`}> {post.title.rendered} </a> </h1> </div> </div> ))} </div> ); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | //src\elements\ViewPage.js import React from 'react' ; import { useEffect, useState } from 'react' ; import { useParams } from "react-router-dom" ; export default function Posts() { const {slug}=useParams(); const [posts, setData] = useState(null); useEffect(()=>{ fetchPost(); },[slug]); const fetchPost=async()=>{ try { const response = await fetch( "http://localhost:8888/cairocoders/wp-json/wp/v2/posts?_embed&slug=" +slug); if (!response.ok) { // oups! something went wrong return ; } const posts = await response.json(); //console.log(posts); setData(posts); } catch (err){ console.log( "Something Wrong" ); } } return ( <div className= "min-h-screen flex items-center justify-center bg-slate-100" > <div className= "bg-white rounded-sm shadow p-8" > {posts && posts.map((post, index) => ( <div key={index}> <h1 className= "text-2xl font-bold mb-5" >{post.title.rendered}</h1> <div className= "mb-4" > <div dangerouslySetInnerHTML={{ __html: post[ 'content' ][ 'rendered' ] }} /> </div> </div> ))} </div> </div> ); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | //themes\cairocoders\functions.php <?php /** * Theme functions and definitions * * @package cairocoders */ add_action( 'rest_api_init' , 'register_rest_images' ); function register_rest_images(){ register_rest_field( array ( 'post' ), 'fimg_url' , array ( 'get_callback' => 'get_rest_featured_image' , 'update_callback' => null, 'schema' => null, ) ); } function get_rest_featured_image( $object , $field_name , $request ) { if ( $object [ 'featured_media' ] ){ $img = wp_get_attachment_image_src( $object [ 'featured_media' ], 'app-thumb' ); return $img [0]; } return false; } |
http://localhost:3000/