اذهب إلى المحتوى

Abdullah Muhammad

الأعضاء
  • المساهمات

    118
  • تاريخ الانضمام

  • تاريخ آخر زيارة

كل منشورات العضو Abdullah Muhammad

  1. قم بتحميل النسخة الأخيره من node من هنا في حالة لم يعمل الأمر معك قم بإتباع الخطوات التاليه قم بإنشاء مجلد بإسم "nodejs" في أحد المسارين التاليين "C:\Program Files (x86)" أو "C:\Program Files" من قائمة start قم بالبحث عن "edit the system environment variables" وقم بفتحها من قائمة Advanced قم بالضغط على Environment Variables في الجزء العلوي قم بالبحث عن "path" وقم بالضغط عليها سوف تنبثق لك نافذه (مرفق صورة للتوضيح) قم بالضغط على "New" ومن ثم قم بلص المسار الذي أنشأت فيه المجلد في الخطوه واحد سيكون بالشكل“C:\Program Files (x86)\nodejs” أو “C:\Program Files \nodejs “. بعد ذلك قم بالضغط على "OK" قم بإستخدام الأمر مرة أخرى وسوف يعمل معك بإذن الله
  2. بكل بساطه يمكنك القيام بالخطوات التاليه 1- قم بإنشاء ملف .env في المسار الرئيسي للمشروع الخاص بك لاتنسى أن تقوم بإضافة إسم هذا الملف إلى ملف ".gitignore" 2- في ملف .env قم قم بإضافة التالي HTTPS=true 3- قم بتشغيل المشروع بالطريقة المعتاده لذلك سوف يظهر لك التحذير المرفق قم بالضغط على "Advanced" ثم "Proceed to localhost (unsafe)" وسوف يعمل معك المشروع بالشكل المطلوب
  3. يمكنك القيام بذلك بشكل بسيط دون الإستعادنه بأي مكتبات خارجيه عن طريق عمل capture للإيفنت الخاص بال error عن طريق إضافة الكود التالي في الملف "public/index.html" في الجزء الخاص ب ال "head" <script> window.addEventListener('error', function(e){ // قم بمنع ريأكت من تشغيل ال listener الخاص بهم e.stopImmediatePropagation(); // منع المتصفح من عمل console.log للإيرور أيضا e.preventDefault(); }); </script> في حالة كنت تريد إستخدام error overlay في أي خطأ خارج ال error boundary يمكنك إستخدام الكود التالي <script> window.addEventListener('error', function(e){ const {error} = e; if (!error.captured) { error.captured = true; e.stopImmediatePropagation(); e.preventDefault(); setTimeout(()=>{ if (!error.shouldIgnore) { throw error; } }) } }); </script>
  4. أغلب الإجابات ليس لها علاقه ب React بشكل كبير لعدم وجود فرق onChange و onInput في ريأكت ولكن الفرق يظهر في حالة كنت تستخدم vanilla js حيث أن onInput: سوف يعمل بالضبط مثل onChange في ريأكت. أي عند تغير أي قيمه داخل ال input سوف يتم تنفيذ الكول باك الموجود داخل ال onInput يمكنك تجربة هذا الأمر من خلال هذا الرابط onChange: سوف يعمل فقط بعد الإنتهاء من كتابة ماتريد داخل ال input والضغط على أي شئ خارج الإنبوت أي عمل focus على أي شئ أخر. يمكنك تجربة وملاحظة الفرق بين onChange و onInput في كلا من ريأكت و جافاسكريبت من خلال هذا الرابط
  5. يمكنك أن تقوم بذلك من خلال إستدعاء ملف ال package.json طالما تستخدم react-scripts بإصدار 1.0.11 فما أحدث وذلك كالتالي import packages from '/package.json' بعد ذلك لكي تستطيع الوصول إلى ماتريد فلاحظ أنها تنقسم إلى قسمين: dependencies devDependencies ولكي تستطيع أن تحصل على هذه البيانات كل ماعليك هو القيام بالتالي const dependencies = {...packages.dependencies, ...packages.devDependencies} وسوف تحصل في النهايه على object يحتوي على كل المكتبات التي تستخدمها بالإضافة الى الإصدار الخاصه بكل مكتبه وتقوم بعرضها كما تشاء. ويمكنك إستخدام الكود التالي لعرضهم كما تريد بحيث يظهر عنصر ul بداخلة عنصر li لكل مكتبة مثبتة مع إصدارها أيضًا. const dependencies = { ...packages.dependencies, ...packages.devDependencies }; const modifiedDependancies = []; for (const i in dependencies) { modifiedDependancies.push({ name: i, version: dependencies[i] }); } return ( <ul> {modifiedDependancies.map((item) => ( <li key={item.name}> {item.name} : {item.version} </li> ))} </ul> );
  6. لكي تستعمل الروابط النشطه داخل ال navbar الخاص بالموقع وتستطيع أن تعطي لهم تنسيق معين في حالة وجعل ال Home Link نشطًا بمجرد بدء التطبيق لابد من إستعمال المكون NavLink المرفق ب react-router داخل ال navbar الخاص بك <NavLink exact={true} activeClassName='is-active' to='/'>Home</NavLink> <NavLink activeClassName='is-active' to='/about'>About</NavLink> <NavLink activeClassName='is-active' to='/users'>Users</NavLink> عند بدء التطبيق سوف يكون اللينك الخاص ب Home هو النشط وسوف يأخذ التنسيق الخاص بالكلاس "is-active" وعند التنقل بين الروابط سوف يطبق التنسيق على الرابط النشط.
  7. في حالة كان الرد من السيرفر ب أوبجكت يحتوي على عدة objects وتحتاج الى أن تقوم بعمل loop عليهم وهذا قلما يكون الوضع يمكنك بالفعل إستيراد كافة ال objects الداخليه لل object الرئيسي ووضعهم داخل مصفوفة كالتالي Object.values(response) وسوف تحصل على مصفوفة كامله من ال objects داخل ال object الرئيسي وبعد ذلك يمكنك عمل loop عليهم لعرضهم داخل المكون بكل سهوله Object.values(response).map(item => {...})
  8. يمكنك أن تستخدم الخطاف useHistory لتحقيق ذلك قم بإستيراد الخطاف import { useHistory } from "react-router-dom" قم بإستدعاءه داخل المكون const history = useHistory() قم بإنشاء الدالة المسئوله عن التعامل مع هذا الحدث const handleParams = (query) => { const params = new URLSearchParams(); if (query) { params.append("color", query); } else { params.delete("color"); } history.push({ search: params.toString() }); }; وبهذا يمكنك تنفيذ ماتريد. يمكنك أيضا أن تجعل قيمة ال query عباره عن قيمه مخزنه داخل ال state وتستخدم الدالة في الخطوة رقم 3 مع useEffect لتحديث ال query في حالة كنت تريد مثلا إستخدام مدخل للبحث أو شئ من هذا القبيل كالتالي const SearchInput = () => { const [query, setQuery] = useState(""); const history = useHistory(); const onChange = (e) => { setQuery(e.target.value); } useEffect(() => { const params = new URLSearchParams(); if (query) { params.append("color", query); } else { params.delete("color"); } history.push({ search: params.toString() }); }, [query, history]); return <input type="text" value={query} onChange={onChange} />; };
  9. عن طريق عمل مصفوفه من الخيارات التي تم تحديدها وذلك كالتالي export default function Select() { const [state, setState] = useState(); const handleChange = (e) => { let value = Array.from(e.target.selectedOptions, (option) => option.value); setState(value); }; return ( <div> <select name="select" multiple={true} onChange={handleChange}> <option value={1}>First option</option> <option value={2}>Second option</option> <option value={3}>Third option</option> </select> </div> ); }
  10. يمكنك إستخدام الحدث (Event) onMouseOver كالتالي function Test() { const changeColor = (color) => {....}; return ( <div> <p onMouseOver={changeColor}>Hello</p> </div> ); } ولكن هذا في حالة كنت تستخدم عنصر HTML عادي أما في حالة إستخدام مكون ريأكت ماعليك إلا إن تجعلها ضمن ال props الخاصه بهذا المكون ومن ثم إستخدامها داخل المكون على سبيل المثال كالتالي function Test() { const changeColor = (color) => {...} return ( <div> <Post onMouseOver={changeColor}></Post> </div> ) } const Post = (props) => { return ( <p onMouseOver={props.onMouseOver}>Content</p> ) }
  11. لديك عدة طرق أرفق لك منها إثنتين 1- بإستخدام ال state export default function Send() { const[buttonDisabled, setButtonDisabled] = useState(false); // الخطوة 1 const handleSubmit = () => { setButtonDisabled(true) // الخطوة 2 axios.post(...).then(res => {...}).catch(err => ...) } return ( <div> // .... الخطوة 3 <button disabled={buttonDisabled} onClick={handleSubmit}>send</button> </div> ) } 2- بإستخدام ال refs export default function Send() { const buttonRef = useRef(); // الخطوة رقم 1 const handleSubmit = () => { // الخطوة رقم 2 if(buttonRef.current){ buttonRef.current.setAttribute("disabled", "disabled"); } axios.post(...).then(res => {...}).catch(err => ...) } return ( <div> ....// الخطوة رقم 3 <button ref={buttonRef} onClick={handleSubmit}>send</button> </div> ) }
  12. وعليكم السلام ورحمة الله وبركاته عملية الخوف من عدم تحقيق شئ في المجال أمر طبيعي لحل هذا الأمر عليك بتقسيم أهداف على المدى القصير والبدء على الفور في تنفيذها قم ببناء مشاريع كثيره على كل ما تتعلمه حتى لو أشياء بسيطه جدا جدا هذا سيعطيك ثقه في نفسك أكثر لاتقع في فخ أن تشاهد شروحات وتطبق فقط وراء الشرح دون القيام بمشروع بسيط بنفسك دون إتباع كود شخص ما أخيرا لا تتعجل خذ وقتك وحاول أن تقدم على تدريب داخل شركات سيعطيك هذه التجربه نظره أوسع عن شكل المجال والعمل الحقيقي وتكتسب خبره كبيره أيضا باذن الله بالتوفيق إن شاء الله
  13. بجانب أن redux منتشر بشكل أكبر ومطلوب في الشركات بإختصار كلا من redux و flux لهما تقريبا نفس البنيه التحتيه (architecture) ولكن Redux تكون أبسط بشكل كبير وتزيل عنك جزء كبير من التعقيد وذلك من خلال إستخدام (functional composition) بينما Flux تستخدم "callback registration" بالإضافه الى أن التعامل مع Redux وتجربتها للمطورين يكون أفضل بسبب سهولة عملية ال debugging وتوفر الإضافة الخاصه ب Redux DevTools.
  14. السبب في ذلك أن React كما أجبتك سابقا لاتقوم بتحديث ال state مباشرة في حالة كنا خارج عملية غير تزامنيه (Asynchronous) بل تقوم بعمل batching وتقوم بعملية التحديث لعدة قيم في ال state مرة واحده حتى لا يحدث render عدد كثير من المرات ولذا بما أنك تستخدم ال hooks يمكنك أن تستخدم ال useEffect لتنفيذ المطلوب عن طريق التالي: useEffect(() => { console.log(username); }, [username]); حيث سيتم تنفيذ الكود فقط في حالة تغيرت قيمة ال username في ال State وفي حالة أردت تنفيذ نفس الأمر في حالة كنت تستخدم class component يمكنك أن تنفذ الأمر كالتالي: render() { return ( <input value={this.state.username} onChange={(e) => { this.setState({ username: e.target.value }, () => { console.log(this.state.username); }); }} /> ); }
  15. أجل يمكنك إستخدام الطريقة التاليه والتي تسمى ternary operator {this.props.found? <h1>Some Content</h1> : <h1>Not Found<h1/>} ففي حالة كان هناك props.found سوف يتم عرض المكون الذي يحوي some content وإلا فسيتم عرض المكون الذي يحتوي على Not Found
  16. تسمى المدخلات التي تسجل قيمتها في ال state وكذلك يكون لها onChange handler ب "Controlled Input" ولذا لابد من استخدام ال state وال handler ولكن يمكننا توفير كتابة handler لكل input وكتابة handler واحد فقط للجميع كالتالي handleChange(e){ const { name, value } = e.target; this.setState({ [name]: value }) } بحيث يكون ال name هو الاسم المسجل داخل ال state لهذا ال input. وأيضا لتسهيل كتابة ال state عليك طالما أنت تستخدم ال hooks ف الأفضل في هذه الحاله أن تستخدم useReducer كالتالي const [input, setInput] = useReducer( (state, newState) => ({ ...state, ...newState }), { name1: "", // هنا أسماء المدخلات name2: "", name3: "" } ); const handleChange = e => { const { name, value } = e.target; setInput({ [name]: value }); }; هناك أيضا مكتبات خارجيه تساعدك وتسهل عليك الأمر أكثر وأكثر يمكنك الإطلاع عليها أرشح لك منها react hook form Formik
  17. بكل بساطة في ملف ال test الخاص بهذه الدالة يمكنك أن تفعل التالي // الخطوة 1 import { getPosts } from "./path"; jest.mock("axios"); describe("getPosts", () => { // الخطوة 2 it("fetches posts successfully", async () => { const response = { // الخطوة 3 data: { posts: [ { postId: "1", postTitle: "Title Title" }, { postId: "2", postTitle: "Title2 Title2" } ] } }; // الخطوة 4 axios.get.mockImplementationOnce(() => Promise.resolve(response)); await expect(getPosts(`${my_URL}`)).resolves.toEqual(response); }); it("fetching posts failed", async () => { const errorMessage = "Network Error"; axios.get.mockImplementationOnce(() => Promise.reject(new Error(errorMessage)) ); await expect(getPosts(`${my_URL}`)).rejects.toThrow(errorMessage); }); }); ففي الخطوة رقم 1 : تقوم بإستيراد الدالة التي تريد عمل لها test في الملف الخاص ب ال test كما نقوم بإعلام jest اننا نقوم بعملية إختبار لدالة asynchronous تستخدم axios الخطوة رقم 2 : تبدأ بتعريف ماتقوم بعمل إختبار له "test" الخطوة رقم 3 : تقوم بكتابة شكل الرد المنتظر في حالة نجاح عملية جلب ال posts وهنا تسمى ب "mock response data" وهي أيضا البيانات الوهمية التي تسئل عنها. الخطوة رقم 4 : تقوم بمدج axios مع هذا الإختبار وكتابة النتيجه المتوقعه من هذا الإختبار الخطوات السابقه تمت في حالة نجاح عملية جلب المقالات ومابعدها يحاكي عملية الفشل.
  18. في البداية دعنا نفهم كيف يعمل ال router على سبيل المثال إذا كان عنوان الموقع الخاص بنا www.example.com فحين الولوج الى الموقع يقوم الروتر بأخذ مابعد .com وهنا الإفتراضي هو "/"والبحث عنه بأسلوب إذا وجدت اي مسار داخل ال BrowserRouter يبدأ ب "/" فقم بعرض المكون الخاص بهذا المسار ولذا ففي المثال المرفق حينما تقوم بتغير المسار إالى "www.example.com/profile" يقوم الروتر بإقتطاع الجزء بعد .com وهو "profile/" ويذهب ليبحث ويرى أي مسار يبدأ بأي شئ يطابق "profile/" في الترتيب حيث أن اول جزء هو "/" فيكون متطابقا مع أول مسار "/" فيقوم بعرض المكون الخاص به ولذا فيمكننا حل هذا الأمر بعدة طرق منها التالى: 1- إستخدام Switch import React from "react"; import ReactDOM from "react-dom"; import { Route, Switch } from "react-router"; import { BrowserRouter } from "react-router-dom"; import People from "./components/People"; import Profile from "./components/Profile"; ReactDOM.render( <BrowserRouter> <Switch> <Route path="/" component={People} /> <Route path="/profile" component={Profile} /> </Switch> </BrowserRouter>, document.getElementById("root") ); 2- إستخدام كlلة exact ك props وبالتي سيطابق المسار الموجود بالجزء المقتطع تماما ReactDOM.render(( <BrowserRouter> <Route exact path="/" component={People} /> <Route exact path="/profile" component={Profile} /> </BrowserRouter> ), document.getElementById('root'))
  19. جميل جدا هذا السؤال يمكنك أن تستخدم الكود التالي return React.createElement(this.props.tagName , this.props, this.props.content); بكل بساطة الطريقة الأسهل التي نستخدمها لكتابة مكونات ريأكت تسمى ب jsx وهي تبسيط للشكل المرفق لا أكثر ففي حالتنا يمكننا إستخدام الكود المرفق لانشاء المكون بالشكل الذي تريده بطريقة بسيطه حيث أن: this.props.tagName: هي اسم المكون الذي تريده على سبيل المثال في حالتنا هذه h1 أو h2 أو h3....إلخ this.props: هنا كل ال props يتم إعطاءها للمكون this.props.content: هنا كل ال children أو الأبناء لهذا المكون وفي حالتنا هذه هو المحتوى الذي نود عرضه فعلى سبيل المثال لو كتبنا بطريقة jsx الكود التالي <ComponentName color="blue" shadowSize={2}> Content Content </ComponentName> ف ريأكت تقوم بتحويل هذا الكود إلى الكود التالي وتتعامل معه React.createElement( ComponentName, {color: 'blue', shadowSize: 2}, 'Content Content' ) عسى أن يكون الأمر واضحا ومبسطا. بالتوفيق إن شاء الله.
  20. هناك طريقتين الأولى : عن طريق إستخدام ال onLayout event ومن خلاله يمكنك الحصول على: الطول العرض الإحداثي x الإحداثي y وذلك كالاتي : export default class measure extends Component { constructor(props) { super(props); this.state = { measurements: {}, } } render() { return ( <View> <View onLayout={({ layoutEvent}) => { this.setState({ measurements: layoutEvent.layout }) }} > <Text>Measure Me</Text> </View> <View> <Text>Width: {this.state.measurements.width}</Text> <Text>Height: {this.state.measurements.height}</Text> <Text>X: {this.state.measurements.x}</Text> <Text>Y: {this.state.measurements.y}</Text> </View> </View> ); } } الطريقة الثانية: بإستخدام (UIManager و findNodeHandle) وذلك كالتالي: import React, { Component } from 'react'; import { Text, View, TouchableOpacity, UIManager, findNodeHandle } from 'react-native'; export default class measure extends Component { constructor(props) { super(props); this.state = { measurements: {}, } } measure() { // الخطوة الثالثة UIManager.measure(findNodeHandle(this.view), (x, y, width, height) => { this.setState({ measurements: { x, y, width, height } }) }) } render() { return ( <View> <View ref={ref => this.view = ref} // الخطوة الأولى > <Text>Measure Me</Text> </View> <TouchableOpacity onPress={() => this.measure() // الخطوة الثانية}> <Text>Measure With UIManager</Text> </TouchableOpacity> <View> <Text>Width: {this.state.measurements.width}</Text> <Text>Height: {this.state.measurements.height}</Text> <Text>X: {this.state.measurements.x}</Text> <Text>Y: {this.state.measurements.y}</Text> </View> </View> ); } } بالتوفيق إن شاء الله.
  21. قبل البداية في الرد على السؤال لديك خطأ بسيط في كتابة أسماء الدوال التاليه عند إستدعائها داخل الداله handleClick وهما setfirstState و setsecondState والصحيح setFirstState و setSecondState ننتقل الى لب السؤال بكل بساطة لدينا حالتين نقوم بعمل تحديث لل state فيها الحالة الأولى: إذا كنا داخل عملية غير تزامنيه (asynchronously) ففي هذه الحاله لا يتم عمل batching بل لكل تحديث لل State سوف يتم عملية render كامله كما هو الحال في الكود الخاص بك المرفق في السؤال. الحالة الثانية: في حالة قمنا بتحديث ال state مباشرة ودون التواجد داخل أي عملية غير تزامنيه فهنا يتم تنفيذ ال batching وتتم عملية ال render مرة واحدة فقط ويمكننا تعديل الكود الخاص بك قليلا كمثال على ذلك كالتالي function Component() { const [firstState, setFirstState] = useState('first'); const [secondState, setSecondState] = useState('second'); function handleClick() { setfirstState('First State Changed'); setsecondState('Second State Changed'); } return ( <button onClick={handleClick}> {firstState} <br /> {secondState} </button> ) } بالتوفيق إن شاء الله.
  22. الأمر بسيط جدا دعنا نأخذ خطوة الى الوراء ونسئل ماهو ال Redirect ؟ بكل بساطه هو مكون موجود في ريأكت روتر من خلاله يمكنك تحويل المستخدم الى مسار أخر حسنا ولكي تقوم ريأكت بعرض مكون لابد من أن تقوم بعملية render ومن ضمن الأمور التي تجبر ريأكت على عملية الريندر أن يتم تغير ال state. جميل حتى هنا الامور بسيطه لذا فلكي تقوم ريأكت بالإستجابة إلى ما أخبرها به وتحويل المستخدم إلى مسار أخر لابد من أن تيم تحديث ال state بقيمة أريدها وعليها يتم التحويل فيكننا بكل بساطة بإستخدام الكود التالي import React, { PropTypes } from 'react'; import { Redirect } from 'react-router' import axios from 'axios'; import AppForm from '../../components/Form'; class FormPage extends React.Component { constructor(props) { super(props); this.state = { redirect: false, // التعديل رقم 1 errors: {}, user: { username: '', email: '', password: '', confirmPassword: '' } }; this.handleForm = this.processForm.bind(this); this.changeUser = this.changeUser.bind(this); } changeUser(event) { const target = event.target; const field = target.name; const user = this.state.user; user[field] = target.value; this.setState({ user.field: field }); } async handleForm(event) { event.preventDefault(); const username = this.state.user.username; const email = this.state.user.email; const password = this.state.user.password; const confirmPassword = this.state.user.confirmPassword; const formData = { username, email, password, confirmPassword }; axios.post('/register', formData, { headers: {'Accept': 'application/json'} }) .then((response) => { this.setState({ errors: {}, redirect: true, // التعديل رقم 2 }); }).catch((error) => { const errors = error.response.data.errors ? error.response.data.errors : {}; errors.summary = error.response.data.message; this.setState({ errors }); }); } render() { if(this.state.redirect) return <Redirect to="" /> // التعديل رقم 3 return ( <> <div> <AppForm onSubmit={this.handleForm} onChange={this.changeUser} errors={this.state.errors} user={this.state.user} /> </div> </> ); } } export default FormPage; قمنا هنا ب ثلاثة تعديلات بسيطه التعديل رقم 1: قمنا بإضافة خاصية جديده داخل ال state تسمى ب redirect وقيمتها ب false التعديل رقم 2: في الكود الذي تعدل فيه قيمة ال State حدثنا أيضا قيمة ال redirect التعديل رقم 3: بما أننا حدثنا ال state ف ريأكت سوف تقوم بالبحث داخل الداله render وترى هل نعتمد على القيم التي تم تغيرها في ال state لعرض مكون معين؟ إذا كانت الإجابه بنعم فتقوم بتنفيذ ال render مرة أخرى وبالتالي سوف يتحقق الشرط المكتول لتنفيذ عملية ال redirect ويتم عرض مكون Redirect الذي بدوره يقوم بتحويل المستخدم إلى المسار الذي تريد.
  23. عملية التنظيم والهيكلة للمشروع تختلف بطبيعة الحال بإختلاف المشروع على إفتراض أن المشروع كبير مثلما تقول ويتم إستهلاك الكثير من الوقت في عملية الهيكله فيمكنك إتباع ال modular pattern حيث تقوم بقسيم المشروع الى عدة وحدات كل وحدة تحتوي علي فولدر خاص ب components الخاصه بهذه الوحدة بالاضافة الى فولدر services الخاص باللوجيك المسئول عن ال API وفولدر __tests__ يحوي عملية الاختبار لهذه الوحده في حالة كنت تريده فيكون على سبيل المثال تقسم المشروع كالتالي: ├── src │ ├── globals │ │ ├── contexts - يحتوي علي أي كونتكست │ │ ├── core.service.js - يحتوي على اللوجيك المستخدم مع ال API المشترك في المشروع بأكمله │ │ └── routes.js - يحتوي على جميل المسارات │ ├── index.js - الملف الرئيسي │ ├── modules - الوحدات المكونه للمشروع │ │ ├── blog │ │ │ ├── components │ │ │ │ ├── blogCard │ │ │ │ │ ├── index.js │ │ │ │ │ └── style.module.css │ │ │ │ ├── blogListPage │ │ │ │ │ ├── index.js │ │ │ │ │ └── style.module.css │ │ │ │ ├── CategoriesFilter │ │ │ │ │ ├── index.js │ │ │ │ │ └── style.module.css │ │ │ │ ├── SearchFilter │ │ │ │ │ ├── index.js │ │ │ │ │ └── style.module.css │ │ │ │ └── singleBlogPage │ │ │ │ ├── index.js │ │ │ │ └── style.module.css │ │ │ ├── services │ │ │ │ ├── blog.service.js │ │ │ │ └── category.service.js │ │ │ └── __tests__ │ │ ├── contact │ │ │ ├── components │ │ │ │ ├── form │ │ │ │ │ ├── index.js │ │ │ │ │ └── style.module.css │ │ │ │ ├── icon │ │ │ │ │ ├── index.js │ │ │ │ │ └── style.module.css │ │ │ │ └── page │ │ │ │ ├── index.js │ │ │ │ └── style.module.css │ │ │ ├── services │ │ │ │ └── contact.service.js │ │ │ └── __tests__ │ │ ├── events │ │ │ ├── components │ │ │ │ ├── ApplyButton │ │ │ │ │ ├── ApplyButton.js │ │ │ │ │ └── style.module.css │ │ │ │ ├── eventCard │ │ │ │ │ ├── index.js │ │ │ │ │ └── style.module.css │ │ │ │ ├── EventDetails │ │ │ │ │ ├── index.js │ │ │ │ │ └── style.module.css │ │ │ │ ├── eventsListPage │ │ │ │ │ ├── index.js │ │ │ │ │ └── style.module.css │ │ │ │ ├── eventsSection │ │ │ │ │ ├── index.js │ │ │ │ │ └── style.module.css │ │ │ │ ├── Gallery │ │ │ │ │ ├── index.js │ │ │ │ │ └── style.module.css │ │ │ │ ├── PopupContent │ │ │ │ │ ├── PopupContent.js │ │ │ │ │ └── style.module.css │ │ │ │ └── singleEventPage │ │ │ │ ├── index.js │ │ │ │ └── style.module.css │ │ │ ├── services │ │ │ │ └── events.service.js │ │ │ └── __tests__ │ │ ├── static-pages │ │ │ ├── about │ │ │ │ └── components │ │ │ │ ├── page │ │ │ │ │ ├── components │ │ │ │ │ │ ├── header │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ └── style.module.css │ │ │ │ │ │ ├── sectionName │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ └── style.module.css │ │ │ │ │ │ ├── sectionName │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ └── style.module.css │ │ │ │ │ │ └── structureSection │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ └── style.module.css │ │ │ │ │ ├── index.js │ │ │ │ │ └── style.module.css │ │ │ │ ├── section │ │ │ │ │ ├── index.js │ │ │ │ │ └── style.module.css │ │ │ │ └── video │ │ │ │ └── index.js │ │ │ └── home │ │ │ ├── components │ │ │ │ ├── bestProjects │ │ │ │ │ ├── index.js │ │ │ │ │ └── style.module.css │ │ │ │ ├── intro │ │ │ │ │ ├── index.js │ │ │ │ │ └── style.module.css │ │ │ │ └── page │ │ │ │ ├── index.js │ │ │ │ └── style.module.css │ │ │ ├── services │ │ │ │ └── clients.service.js │ │ │ └── __tests__ │ │ └── teamServices │ │ ├── components │ │ │ ├── singleServicePage │ │ │ │ ├── index.js │ │ │ │ └── style.module.css │ │ │ └── teamServicesSection │ │ │ ├── index.js │ │ │ └── style.module.css │ │ ├── store │ │ │ └── services.json │ │ └── __tests__ │ │ ├── singleServiceSection.test.js │ │ └── __snapshots__ │ ├── serviceWorker.js │ ├── shared │ │ ├── footer │ │ │ ├── index.js │ │ │ └── style.module.css │ │ ├── header │ │ │ ├── index.js │ │ │ └── style.css │ │ ├── Image-loader │ │ │ ├── index.js │ │ │ └── style.css │ │ ├── Input.js │ │ ├── layout │ │ │ ├── index.js │ │ │ └── style.css │ │ ├── lazy-image │ │ │ └── index.js │ │ ├── loading │ │ │ └── index.js │ │ ├── newsletterForm │ │ │ ├── index.js │ │ │ └── style.module.css │ │ ├── notFoundPage │ │ │ ├── index.js │ │ │ └── style.module.css │ │ ├── services │ │ │ ├── date.service.js │ │ │ ├── image.service.js │ │ │ ├── language.service.js │ │ │ ├── newsletter.service.js │ │ │ └── validation.service.js │ │ ├── sideDrawer │ │ │ ├── index.js │ │ │ └── style.module.css │ │ ├── __tests__ │ │ │ ├── footer.test.js │ │ │ ├── header.test.js │ │ │ ├── newsLetter.test.js │ │ │ ├── sideDrawer.test.js │ │ │ └── themeBtn.test.js │ │ └── theme-button │ │ ├── index.js │ │ └── style.css │ └── styles.css وهذا مثال على تخطيط وتنظيم لمشروع متوسط نوعا ويتيح لك الإمكانية للتوسع في المستقبل دون معاناه ودون إستهلاك الكثير من الوقت حيث أن المشروع مقسم وحدات وكل وحدة منعزلة بمفردها حتى في حالة أردت إستخدام وحدة كاملة في مشروع أخر فيمكنك فقط نسخ الفولدر الخاص بها كاملا ونقله الى المشروع الذي تريد دون أي معاناة تذكر.
  24. يمكنك إستخدام هذا السيرفر حيث ترسل اليه الداتا التي يتم ملئها في صفحة التواصل وتحدد الرد المناسب الذي يساعدك من غرض التحقق كل ماعليك هو 1- إختيار الميثود وليكن POST 2- إختيار ال status code وليكن 201 created 3- إنشاء الجسم الخاص بالرد وليكن { "status": "success", "message": "we recived your message" } بعد ذلك سوف يتم إنشاء رابط لك تستخدمه في عملية التستينج التي تريدها ويكون الرابط على الشكل التالي: api.mocki.io/v1/007381ae كل ماعليك هو إرسال بيانات الى هذا الرابط بإستخدام نفس الميثود التي حددتها في الخطوة الأولى. في حالة كنت تود إرسال الرساله الى إيميل حقيقي مثل Gmail مثلا فهذا لايتم من خلال الفرونت إند بل لابد أن يتم إرسال الايميل الى السيرفر والسيرفر هو من يتولى عملية الإرسال عن طريق مايسمى بال "SMTP" وفي هذه الحالة أيضا تظل كافة الخطوات التى قمنا بها ثابته حيث نرسل الداتا الى السيرفر وهو يرسلها الى الإيميل.
  25. لتنفيذ هذا الأمر دعنا نقسم العمل على خطوات 1- نود معرفة تاريخ انتهاء التوكن 2- نود معرفة هل انتهى التوكن في الوقت الحالي أم لا 3- إذا إنتهى التوكن نود تسجيل الخروج الخطوة الأولى معرفة تاريخ الإنتهاء يمكننا تحقيق هذه الخطوة من خلال إستخراج بعض الداتا التي يحملها التوكن الذي يتم تخزينه في LocalStorage وتكون مشفره كالتالي: const getExpirationDate = (token) => { if (!token) { return null; } const jwt = JSON.parse(atob(token.split('.')[1])); // نقوم بعملية الضرب في 1000 هنا فقط للتحويل الى مللي ثانية return jwt && jwt.exp && jwt.exp * 1000 || null; }; الخطوة الثانية التأكد هل إنتهت صلاحية التوكن أم لا وذلك بإستخدام الدالة التاليه: const isExpired = (exp) => { if (!exp) { return false; } return Date.now() > exp; }; الخطوة الثالثه نريد إستخدام ماكتبناه حتى الان للتحديد هل تم الانتهاء وتسجيل الخروج أم لا في الجزء المخصص في الكود الذي تقوم فيه بجلب التوكن من اللوكال ستورج بعد جلب التوكن نقوم بعمل هذا الشرط للتكفل بباقي الأمر if(isExpired(getExpirationDate(accessToken)){ localStorage.clear(); // هنا نقوم بحذف التوكن من اللوكال ستورج history.push('/login'); // نقوم بتوجيه المستخدم الى صفحة تسجيل الدخول مرة أخرى } وبذلك يكون قد حققنا ماتريده. هناك طريقة أخرى إذا كنت لا تريد أن تقوم بتسجيل الخروج بل تريد أن تقوم بتجديد التوكن فقط حيث تعتمد هذه الطريقه على مايسمى بال Refresh Token.
×
×
  • أضف...